Skip to main content

ecdsa/
der.rs

1//! Support for ASN.1 DER-encoded ECDSA signatures as specified in
2//! [RFC5912 Section 6].
3//!
4//! [RFC5912 Section 6]: https://www.rfc-editor.org/rfc/rfc5912#section-6
5
6use crate::{EcdsaCurve, Error, Result};
7use core::{
8    fmt::{self, Debug},
9    ops::{Add, Range},
10};
11use der::{
12    Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence, Tag,
13    Writer, asn1::UintRef,
14};
15use elliptic_curve::{
16    FieldBytesSize,
17    array::{Array, ArraySize, typenum::Unsigned},
18    consts::U9,
19};
20
21#[cfg(feature = "alloc")]
22use {
23    alloc::{boxed::Box, vec::Vec},
24    signature::SignatureEncoding,
25    spki::{SignatureBitStringEncoding, der::asn1::BitString},
26};
27
28#[cfg(feature = "serde")]
29use serdect::serde::{Deserialize, Serialize, de, ser};
30
31/// Maximum overhead of an ASN.1 DER-encoded ECDSA signature for a given curve:
32/// 9-bytes.
33///
34/// Includes 3-byte ASN.1 DER header:
35///
36/// - 1-byte: ASN.1 `SEQUENCE` tag (0x30)
37/// - 2-byte: length
38///
39/// ...followed by two ASN.1 `INTEGER` values, which each have a header whose
40/// maximum length is the following:
41///
42/// - 1-byte: ASN.1 `INTEGER` tag (0x02)
43/// - 1-byte: length
44/// - 1-byte: zero to indicate value is positive (`INTEGER` is signed)
45pub type MaxOverhead = U9;
46
47/// Maximum size of an ASN.1 DER encoded signature for the given elliptic curve.
48pub type MaxSize<C> = <<FieldBytesSize<C> as Add>::Output as Add<MaxOverhead>>::Output;
49
50/// Byte array containing a serialized ASN.1 signature
51type SignatureBytes<C> = Array<u8, MaxSize<C>>;
52
53/// ASN.1 DER-encoded signature as specified in [RFC5912 Section 6]:
54///
55/// ```text
56/// ECDSA-Sig-Value ::= SEQUENCE {
57///   r  INTEGER,
58///   s  INTEGER
59/// }
60/// ```
61///
62/// [RFC5912 Section 6]: https://www.rfc-editor.org/rfc/rfc5912#section-6
63pub struct Signature<C>
64where
65    C: EcdsaCurve,
66    MaxSize<C>: ArraySize,
67    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
68{
69    /// ASN.1 DER-encoded signature data
70    bytes: SignatureBytes<C>,
71
72    /// Range of the `r` value within the signature
73    r_range: Range<usize>,
74
75    /// Range of the `s` value within the signature
76    s_range: Range<usize>,
77}
78
79#[allow(clippy::len_without_is_empty)]
80impl<C> Signature<C>
81where
82    C: EcdsaCurve,
83    MaxSize<C>: ArraySize,
84    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
85{
86    /// Parse signature from DER-encoded bytes.
87    ///
88    /// # Errors
89    /// Returns [`Error`] if `input` failed to parse as an ASN.1 DER-encoded ECDSA signature.
90    pub fn from_bytes(input: &[u8]) -> Result<Self> {
91        let SignatureRef { r, s } = SignatureRef::from_der(input).map_err(|_| Error::new())?;
92
93        if r.as_bytes().len() > C::FieldBytesSize::USIZE
94            || s.as_bytes().len() > C::FieldBytesSize::USIZE
95        {
96            return Err(Error::new());
97        }
98
99        let r_range = find_scalar_range(input, r.as_bytes())?;
100        let s_range = find_scalar_range(input, s.as_bytes())?;
101
102        if s_range.end != input.len() {
103            return Err(Error::new());
104        }
105
106        let mut bytes = SignatureBytes::<C>::default();
107        bytes[..s_range.end].copy_from_slice(input);
108
109        Ok(Signature {
110            bytes,
111            r_range,
112            s_range,
113        })
114    }
115
116    /// Create an ASN.1 DER encoded signature from big endian `r` and `s` scalar components.
117    pub(crate) fn from_components(r: &[u8], s: &[u8]) -> der::Result<Self> {
118        let sig = SignatureRef {
119            r: UintRef::new(r)?,
120            s: UintRef::new(s)?,
121        };
122        let mut bytes = SignatureBytes::<C>::default();
123
124        sig.encode_to_slice(&mut bytes)?
125            .try_into()
126            .map_err(|_| Tag::Sequence.value_error().into())
127    }
128
129    /// Borrow this signature as a byte slice
130    pub fn as_bytes(&self) -> &[u8] {
131        &self.bytes.as_slice()[..self.len()]
132    }
133
134    /// Serialize this signature as a boxed byte slice
135    #[cfg(feature = "alloc")]
136    pub fn to_bytes(&self) -> Box<[u8]> {
137        self.as_bytes().to_vec().into_boxed_slice()
138    }
139
140    /// Get the length of the signature in bytes
141    pub fn len(&self) -> usize {
142        self.s_range.end
143    }
144
145    /// Get the `r` component of the signature (leading zeros removed)
146    pub(crate) fn r(&self) -> &[u8] {
147        &self.bytes[self.r_range.clone()]
148    }
149
150    /// Get the `s` component of the signature (leading zeros removed)
151    pub(crate) fn s(&self) -> &[u8] {
152        &self.bytes[self.s_range.clone()]
153    }
154}
155
156impl<C> core::hash::Hash for Signature<C>
157where
158    C: EcdsaCurve,
159    MaxSize<C>: ArraySize,
160    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
161{
162    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
163        self.as_bytes().hash(state);
164    }
165}
166
167impl<C> AsRef<[u8]> for Signature<C>
168where
169    C: EcdsaCurve,
170    MaxSize<C>: ArraySize,
171    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
172{
173    fn as_ref(&self) -> &[u8] {
174        self.as_bytes()
175    }
176}
177
178impl<C> Clone for Signature<C>
179where
180    C: EcdsaCurve,
181    MaxSize<C>: ArraySize,
182    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
183{
184    fn clone(&self) -> Self {
185        Self {
186            bytes: self.bytes.clone(),
187            r_range: self.r_range.clone(),
188            s_range: self.s_range.clone(),
189        }
190    }
191}
192
193impl<C> Debug for Signature<C>
194where
195    C: EcdsaCurve,
196    MaxSize<C>: ArraySize,
197    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
198{
199    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200        write!(f, "ecdsa::der::Signature<{:?}>(", C::default())?;
201
202        for &byte in self.as_ref() {
203            write!(f, "{byte:02X}")?;
204        }
205
206        write!(f, ")")
207    }
208}
209
210impl<'a, C> Decode<'a> for Signature<C>
211where
212    C: EcdsaCurve,
213    MaxSize<C>: ArraySize,
214    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
215{
216    type Error = der::Error;
217
218    fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> {
219        let header = Header::peek(reader)?;
220        header.tag().assert_eq(Tag::Sequence)?;
221
222        let mut buf = SignatureBytes::<C>::default();
223        let len = (header.encoded_len()? + header.length())?;
224        let slice = buf
225            .get_mut(..usize::try_from(len)?)
226            .ok_or_else(|| reader.error(Tag::Sequence.length_error()))?;
227
228        reader.read_into(slice)?;
229        Self::from_bytes(slice).map_err(|_| reader.error(Tag::Integer.value_error()))
230    }
231}
232
233impl<C> Encode for Signature<C>
234where
235    C: EcdsaCurve,
236    MaxSize<C>: ArraySize,
237    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
238{
239    fn encoded_len(&self) -> der::Result<Length> {
240        Length::try_from(self.len())
241    }
242
243    fn encode(&self, writer: &mut impl Writer) -> der::Result<()> {
244        writer.write(self.as_bytes())
245    }
246}
247
248impl<C> FixedTag for Signature<C>
249where
250    C: EcdsaCurve,
251    MaxSize<C>: ArraySize,
252    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
253{
254    const TAG: Tag = Tag::Sequence;
255}
256
257impl<C> From<crate::Signature<C>> for Signature<C>
258where
259    C: EcdsaCurve,
260    MaxSize<C>: ArraySize,
261    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
262{
263    fn from(sig: crate::Signature<C>) -> Signature<C> {
264        sig.to_der()
265    }
266}
267
268impl<C> TryFrom<&[u8]> for Signature<C>
269where
270    C: EcdsaCurve,
271    MaxSize<C>: ArraySize,
272    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
273{
274    type Error = Error;
275
276    fn try_from(input: &[u8]) -> Result<Self> {
277        Self::from_bytes(input)
278    }
279}
280
281impl<C> TryFrom<Signature<C>> for crate::Signature<C>
282where
283    C: EcdsaCurve,
284    MaxSize<C>: ArraySize,
285    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
286{
287    type Error = Error;
288
289    fn try_from(sig: Signature<C>) -> Result<super::Signature<C>> {
290        let mut bytes = super::SignatureBytes::<C>::default();
291        let r_begin = C::FieldBytesSize::USIZE.saturating_sub(sig.r().len());
292        let s_begin = bytes.len().saturating_sub(sig.s().len());
293        bytes[r_begin..C::FieldBytesSize::USIZE].copy_from_slice(sig.r());
294        bytes[s_begin..].copy_from_slice(sig.s());
295        Self::try_from(bytes.as_slice())
296    }
297}
298
299#[cfg(feature = "alloc")]
300impl<C> From<Signature<C>> for Box<[u8]>
301where
302    C: EcdsaCurve,
303    MaxSize<C>: ArraySize,
304    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
305{
306    fn from(signature: Signature<C>) -> Box<[u8]> {
307        signature.to_vec().into_boxed_slice()
308    }
309}
310
311#[cfg(feature = "alloc")]
312impl<C> SignatureEncoding for Signature<C>
313where
314    C: EcdsaCurve,
315    MaxSize<C>: ArraySize,
316    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
317{
318    type Repr = Box<[u8]>;
319
320    fn to_vec(&self) -> Vec<u8> {
321        self.as_bytes().into()
322    }
323}
324
325#[cfg(feature = "alloc")]
326impl<C> SignatureBitStringEncoding for Signature<C>
327where
328    C: EcdsaCurve,
329    MaxSize<C>: ArraySize,
330    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
331{
332    fn to_bitstring(&self) -> der::Result<BitString> {
333        BitString::new(0, self.to_vec())
334    }
335}
336
337#[cfg(feature = "serde")]
338impl<C> Serialize for Signature<C>
339where
340    C: EcdsaCurve,
341    MaxSize<C>: ArraySize,
342    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
343{
344    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
345    where
346        S: ser::Serializer,
347    {
348        serdect::slice::serialize_hex_upper_or_bin(&self.as_bytes(), serializer)
349    }
350}
351
352#[cfg(feature = "serde")]
353impl<'de, C> Deserialize<'de> for Signature<C>
354where
355    C: EcdsaCurve,
356    MaxSize<C>: ArraySize,
357    <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArraySize,
358{
359    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
360    where
361        D: de::Deserializer<'de>,
362    {
363        let mut buf = SignatureBytes::<C>::default();
364        let slice = serdect::slice::deserialize_hex_or_bin(&mut buf, deserializer)?;
365        Self::try_from(slice).map_err(de::Error::custom)
366    }
367}
368
369struct SignatureRef<'a> {
370    pub r: UintRef<'a>,
371    pub s: UintRef<'a>,
372}
373
374impl EncodeValue for SignatureRef<'_> {
375    fn value_len(&self) -> der::Result<Length> {
376        self.r.encoded_len()? + self.s.encoded_len()?
377    }
378
379    fn encode_value(&self, encoder: &mut impl Writer) -> der::Result<()> {
380        self.r.encode(encoder)?;
381        self.s.encode(encoder)?;
382        Ok(())
383    }
384}
385
386impl<'a> DecodeValue<'a> for SignatureRef<'a> {
387    type Error = der::Error;
388
389    fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
390        Ok(Self {
391            r: UintRef::decode(reader)?,
392            s: UintRef::decode(reader)?,
393        })
394    }
395}
396impl<'a> Sequence<'a> for SignatureRef<'a> {}
397
398/// Locate the range within a slice at which a particular subslice is located
399#[allow(clippy::as_conversions)]
400fn find_scalar_range(outer: &[u8], inner: &[u8]) -> Result<Range<usize>> {
401    let outer_start = outer.as_ptr() as usize;
402    let inner_start = inner.as_ptr() as usize;
403    let start = inner_start
404        .checked_sub(outer_start)
405        .ok_or_else(Error::new)?;
406    let end = start.checked_add(inner.len()).ok_or_else(Error::new)?;
407    Ok(Range { start, end })
408}
409
410#[cfg(all(test, feature = "algorithm"))]
411mod tests {
412    use elliptic_curve::dev::MockCurve;
413
414    type Signature = crate::Signature<MockCurve>;
415
416    const EXAMPLE_SIGNATURE: [u8; 64] = [
417        0xf3, 0xac, 0x80, 0x61, 0xb5, 0x14, 0x79, 0x5b, 0x88, 0x43, 0xe3, 0xd6, 0x62, 0x95, 0x27,
418        0xed, 0x2a, 0xfd, 0x6b, 0x1f, 0x6a, 0x55, 0x5a, 0x7a, 0xca, 0xbb, 0x5e, 0x6f, 0x79, 0xc8,
419        0xc2, 0xac, 0x8b, 0xf7, 0x78, 0x19, 0xca, 0x5, 0xa6, 0xb2, 0x78, 0x6c, 0x76, 0x26, 0x2b,
420        0xf7, 0x37, 0x1c, 0xef, 0x97, 0xb2, 0x18, 0xe9, 0x6f, 0x17, 0x5a, 0x3c, 0xcd, 0xda, 0x2a,
421        0xcc, 0x5, 0x89, 0x3,
422    ];
423
424    #[test]
425    fn test_fixed_to_asn1_signature_roundtrip() {
426        let signature1 =
427            Signature::try_from(EXAMPLE_SIGNATURE.as_ref()).expect("decoded Signature");
428
429        // Convert to ASN.1 DER and back
430        let asn1_signature = signature1.to_der();
431        let signature2 = Signature::from_der(asn1_signature.as_ref()).expect("decoded Signature");
432
433        assert_eq!(signature1, signature2);
434    }
435
436    #[test]
437    fn test_asn1_too_short_signature() {
438        assert!(Signature::from_der(&[]).is_err());
439        assert!(Signature::from_der(&[0x30]).is_err());
440        assert!(Signature::from_der(&[0x30, 0x00]).is_err());
441        assert!(Signature::from_der(&[0x30, 0x03, 0x02, 0x01, 0x01]).is_err());
442    }
443
444    #[test]
445    fn test_asn1_non_der_signature() {
446        // A minimal 8-byte ASN.1 signature parses OK.
447        assert!(
448            Signature::from_der(&[
449                0x30, // Tag::Sequence,
450                0x06, // length of below
451                0x02, // Tag::Integer,
452                0x01, // length of value
453                0x01, // value=1
454                0x02, // Tag::Integer,
455                0x01, // length of value
456                0x01, // value=1
457            ])
458            .is_ok()
459        );
460
461        // But length fields that are not minimally encoded should be rejected, as they are not
462        // valid DER, cf.
463        // https://github.com/google/wycheproof/blob/2196000605e4/testvectors/ecdsa_secp256k1_sha256_test.json#L57-L66
464        assert!(
465            Signature::from_der(&[
466                0x30, // Tag::Sequence
467                0x81, // extended length: 1 length byte to come
468                0x06, // length of below
469                0x02, // Tag::Integer
470                0x01, // length of value
471                0x01, // value=1
472                0x02, // Tag::Integer
473                0x01, // length of value
474                0x01, // value=1
475            ])
476            .is_err()
477        );
478    }
479}