Coverage Report

Created: 2026-01-13 06:57

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