From 2c26eaef74472b2c4da5c18da50788ca922bfb53 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 1 Mar 2023 09:19:59 -0700 Subject: [PATCH] ecdsa: add `Decode` and `Encode` impls for `der::Signature` --- ecdsa/src/der.rs | 123 +++++++++++++++++++++++++++++++++-------------- ecdsa/src/lib.rs | 2 +- 2 files changed, 88 insertions(+), 37 deletions(-) diff --git a/ecdsa/src/der.rs b/ecdsa/src/der.rs index 5d63bd8d..321365ef 100644 --- a/ecdsa/src/der.rs +++ b/ecdsa/src/der.rs @@ -5,7 +5,7 @@ use core::{ fmt::{self, Debug}, ops::{Add, Range}, }; -use der::{asn1::UintRef, Decode, Encode, Reader}; +use der::{asn1::UintRef, Decode, Encode, FixedTag, Length, Reader, Tag, Writer}; use elliptic_curve::{ bigint::Integer, consts::U9, @@ -70,24 +70,34 @@ where MaxSize: ArrayLength, as Add>::Output: Add + ArrayLength, { - /// Get the length of the signature in bytes - pub fn len(&self) -> usize { - self.s_range.end - } + /// Parse signature from DER-encoded bytes. + pub fn from_bytes(input: &[u8]) -> Result { + let (r, s) = decode_der(input).map_err(|_| Error::new())?; - /// Borrow this signature as a byte slice - pub fn as_bytes(&self) -> &[u8] { - &self.bytes.as_slice()[..self.len()] - } + if r.as_bytes().len() > C::Uint::BYTES || s.as_bytes().len() > C::Uint::BYTES { + return Err(Error::new()); + } - /// Serialize this signature as a boxed byte slice - #[cfg(feature = "alloc")] - pub fn to_bytes(&self) -> Box<[u8]> { - self.as_bytes().to_vec().into_boxed_slice() + let r_range = find_scalar_range(input, r.as_bytes())?; + let s_range = find_scalar_range(input, s.as_bytes())?; + + if s_range.end != input.len() { + return Err(Error::new()); + } + + let mut bytes = SignatureBytes::::default(); + bytes[..s_range.end].copy_from_slice(input); + + Ok(Signature { + bytes, + r_range, + s_range, + }) } - /// Create an ASN.1 DER encoded signature from big endian `r` and `s` scalars - pub(crate) fn from_scalar_bytes(r: &[u8], s: &[u8]) -> der::Result { + /// Create an ASN.1 DER encoded signature from big endian `r` and `s` scalar + /// components. + pub(crate) fn from_components(r: &[u8], s: &[u8]) -> der::Result { let r = UintRef::new(r)?; let s = UintRef::new(s)?; @@ -105,6 +115,22 @@ where .map_err(|_| der::Tag::Sequence.value_error()) } + /// Borrow this signature as a byte slice + pub fn as_bytes(&self) -> &[u8] { + &self.bytes.as_slice()[..self.len()] + } + + /// Serialize this signature as a boxed byte slice + #[cfg(feature = "alloc")] + pub fn to_bytes(&self) -> Box<[u8]> { + self.as_bytes().to_vec().into_boxed_slice() + } + + /// Get the length of the signature in bytes + pub fn len(&self) -> usize { + self.s_range.end + } + /// Get the `r` component of the signature (leading zeros removed) pub(crate) fn r(&self) -> &[u8] { &self.bytes[self.r_range.clone()] @@ -159,6 +185,51 @@ where } } +impl<'a, C> Decode<'a> for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn decode>(reader: &mut R) -> der::Result { + let header = reader.peek_header()?; + header.tag.assert_eq(Tag::Sequence)?; + + let mut buf = SignatureBytes::::default(); + let len = (header.encoded_len()? + header.length)?; + let slice = buf + .get_mut(..usize::try_from(len)?) + .ok_or_else(|| reader.error(Tag::Sequence.length_error().kind()))?; + + reader.read_into(slice)?; + Self::from_bytes(slice).map_err(|_| Tag::Integer.value_error()) + } +} + +impl Encode for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn encoded_len(&self) -> der::Result { + Length::try_from(self.len()) + } + + fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + const TAG: Tag = Tag::Sequence; +} + impl From> for Signature where C: PrimeCurve, @@ -179,27 +250,7 @@ where type Error = Error; fn try_from(input: &[u8]) -> Result { - let (r, s) = decode_der(input).map_err(|_| Error::new())?; - - if r.as_bytes().len() > C::Uint::BYTES || s.as_bytes().len() > C::Uint::BYTES { - return Err(Error::new()); - } - - let r_range = find_scalar_range(input, r.as_bytes())?; - let s_range = find_scalar_range(input, s.as_bytes())?; - - if s_range.end != input.len() { - return Err(Error::new()); - } - - let mut bytes = SignatureBytes::::default(); - bytes[..s_range.end].copy_from_slice(input); - - Ok(Signature { - bytes, - r_range, - s_range, - }) + Self::from_bytes(input) } } diff --git a/ecdsa/src/lib.rs b/ecdsa/src/lib.rs index 8028d9ab..39a04531 100644 --- a/ecdsa/src/lib.rs +++ b/ecdsa/src/lib.rs @@ -182,7 +182,7 @@ where as Add>::Output: Add + ArrayLength, { let (r, s) = self.split_bytes(); - der::Signature::from_scalar_bytes(&r, &s).expect("DER encoding error") + der::Signature::from_components(&r, &s).expect("DER encoding error") } /// Convert this signature into a byte vector.