/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ecdsa-0.16.9/src/lib.rs
Line | Count | Source |
1 | | #![no_std] |
2 | | #![cfg_attr(docsrs, feature(doc_auto_cfg))] |
3 | | #![doc = include_str!("../README.md")] |
4 | | #![doc( |
5 | | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", |
6 | | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" |
7 | | )] |
8 | | #![forbid(unsafe_code)] |
9 | | #![warn( |
10 | | clippy::cast_lossless, |
11 | | clippy::cast_possible_truncation, |
12 | | clippy::cast_possible_wrap, |
13 | | clippy::cast_precision_loss, |
14 | | clippy::cast_sign_loss, |
15 | | clippy::checked_conversions, |
16 | | clippy::implicit_saturating_sub, |
17 | | clippy::panic, |
18 | | clippy::panic_in_result_fn, |
19 | | clippy::unwrap_used, |
20 | | missing_docs, |
21 | | rust_2018_idioms, |
22 | | unused_lifetimes, |
23 | | unused_qualifications |
24 | | )] |
25 | | |
26 | | //! ## `serde` support |
27 | | //! |
28 | | //! When the `serde` feature of this crate is enabled, `Serialize` and |
29 | | //! `Deserialize` impls are provided for the [`Signature`] and [`VerifyingKey`] |
30 | | //! types. |
31 | | //! |
32 | | //! Please see type-specific documentation for more information. |
33 | | //! |
34 | | //! ## Interop |
35 | | //! |
36 | | //! Any crates which provide an implementation of ECDSA for a particular |
37 | | //! elliptic curve can leverage the types from this crate, along with the |
38 | | //! [`k256`], [`p256`], and/or [`p384`] crates to expose ECDSA functionality in |
39 | | //! a generic, interoperable way by leveraging the [`Signature`] type with in |
40 | | //! conjunction with the [`signature::Signer`] and [`signature::Verifier`] |
41 | | //! traits. |
42 | | //! |
43 | | //! For example, the [`ring-compat`] crate implements the [`signature::Signer`] |
44 | | //! and [`signature::Verifier`] traits in conjunction with the |
45 | | //! [`p256::ecdsa::Signature`] and [`p384::ecdsa::Signature`] types to |
46 | | //! wrap the ECDSA implementations from [*ring*] in a generic, interoperable |
47 | | //! API. |
48 | | //! |
49 | | //! [`k256`]: https://docs.rs/k256 |
50 | | //! [`p256`]: https://docs.rs/p256 |
51 | | //! [`p256::ecdsa::Signature`]: https://docs.rs/p256/latest/p256/ecdsa/type.Signature.html |
52 | | //! [`p384`]: https://docs.rs/p384 |
53 | | //! [`p384::ecdsa::Signature`]: https://docs.rs/p384/latest/p384/ecdsa/type.Signature.html |
54 | | //! [`ring-compat`]: https://docs.rs/ring-compat |
55 | | //! [*ring*]: https://docs.rs/ring |
56 | | |
57 | | #[cfg(feature = "alloc")] |
58 | | extern crate alloc; |
59 | | |
60 | | mod normalized; |
61 | | mod recovery; |
62 | | |
63 | | #[cfg(feature = "der")] |
64 | | pub mod der; |
65 | | #[cfg(feature = "dev")] |
66 | | pub mod dev; |
67 | | #[cfg(feature = "hazmat")] |
68 | | pub mod hazmat; |
69 | | #[cfg(feature = "signing")] |
70 | | mod signing; |
71 | | #[cfg(feature = "verifying")] |
72 | | mod verifying; |
73 | | |
74 | | pub use crate::{normalized::NormalizedSignature, recovery::RecoveryId}; |
75 | | |
76 | | // Re-export the `elliptic-curve` crate (and select types) |
77 | | pub use elliptic_curve::{self, sec1::EncodedPoint, PrimeCurve}; |
78 | | |
79 | | // Re-export the `signature` crate (and select types) |
80 | | pub use signature::{self, Error, Result, SignatureEncoding}; |
81 | | |
82 | | #[cfg(feature = "signing")] |
83 | | pub use crate::signing::SigningKey; |
84 | | #[cfg(feature = "verifying")] |
85 | | pub use crate::verifying::VerifyingKey; |
86 | | |
87 | | use core::{fmt, ops::Add}; |
88 | | use elliptic_curve::{ |
89 | | generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, |
90 | | FieldBytes, FieldBytesSize, ScalarPrimitive, |
91 | | }; |
92 | | |
93 | | #[cfg(feature = "alloc")] |
94 | | use alloc::vec::Vec; |
95 | | |
96 | | #[cfg(feature = "arithmetic")] |
97 | | use { |
98 | | core::str, |
99 | | elliptic_curve::{scalar::IsHigh, CurveArithmetic, NonZeroScalar}, |
100 | | }; |
101 | | |
102 | | #[cfg(feature = "digest")] |
103 | | use digest::{ |
104 | | const_oid::{AssociatedOid, ObjectIdentifier}, |
105 | | Digest, |
106 | | }; |
107 | | |
108 | | #[cfg(feature = "pkcs8")] |
109 | | use elliptic_curve::pkcs8::spki::{ |
110 | | der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, |
111 | | }; |
112 | | |
113 | | #[cfg(feature = "serde")] |
114 | | use serdect::serde::{de, ser, Deserialize, Serialize}; |
115 | | |
116 | | #[cfg(all(feature = "alloc", feature = "pkcs8"))] |
117 | | use elliptic_curve::pkcs8::spki::{ |
118 | | self, AlgorithmIdentifierOwned, DynAssociatedAlgorithmIdentifier, |
119 | | }; |
120 | | |
121 | | /// OID for ECDSA with SHA-224 digests. |
122 | | /// |
123 | | /// ```text |
124 | | /// ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2) |
125 | | /// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 1 } |
126 | | /// ``` |
127 | | // TODO(tarcieri): use `ObjectIdentifier::push_arc` when const unwrap is stable |
128 | | #[cfg(feature = "digest")] |
129 | | pub const ECDSA_SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.1"); |
130 | | |
131 | | /// OID for ECDSA with SHA-256 digests. |
132 | | /// |
133 | | /// ```text |
134 | | /// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) |
135 | | /// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } |
136 | | /// ``` |
137 | | #[cfg(feature = "digest")] |
138 | | pub const ECDSA_SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2"); |
139 | | |
140 | | /// OID for ECDSA with SHA-384 digests. |
141 | | /// |
142 | | /// ```text |
143 | | /// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) |
144 | | /// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } |
145 | | /// ``` |
146 | | #[cfg(feature = "digest")] |
147 | | pub const ECDSA_SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.3"); |
148 | | |
149 | | /// OID for ECDSA with SHA-512 digests. |
150 | | /// |
151 | | /// ```text |
152 | | /// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) |
153 | | /// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } |
154 | | /// ``` |
155 | | #[cfg(feature = "digest")] |
156 | | pub const ECDSA_SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.4"); |
157 | | |
158 | | #[cfg(feature = "digest")] |
159 | | const SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.4"); |
160 | | #[cfg(feature = "digest")] |
161 | | const SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1"); |
162 | | #[cfg(feature = "digest")] |
163 | | const SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.2"); |
164 | | #[cfg(feature = "digest")] |
165 | | const SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.3"); |
166 | | |
167 | | /// Size of a fixed sized signature for the given elliptic curve. |
168 | | pub type SignatureSize<C> = <FieldBytesSize<C> as Add>::Output; |
169 | | |
170 | | /// Fixed-size byte array containing an ECDSA signature |
171 | | pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>; |
172 | | |
173 | | /// ECDSA signature (fixed-size). Generic over elliptic curve types. |
174 | | /// |
175 | | /// Serialized as fixed-sized big endian scalar values with no added framing: |
176 | | /// |
177 | | /// - `r`: field element size for the given curve, big-endian |
178 | | /// - `s`: field element size for the given curve, big-endian |
179 | | /// |
180 | | /// Both `r` and `s` MUST be non-zero. |
181 | | /// |
182 | | /// For example, in a curve with a 256-bit modulus like NIST P-256 or |
183 | | /// secp256k1, `r` and `s` will both be 32-bytes and serialized as big endian, |
184 | | /// resulting in a signature with a total of 64-bytes. |
185 | | /// |
186 | | /// ASN.1 DER-encoded signatures also supported via the |
187 | | /// [`Signature::from_der`] and [`Signature::to_der`] methods. |
188 | | /// |
189 | | /// # `serde` support |
190 | | /// |
191 | | /// When the `serde` feature of this crate is enabled, it provides support for |
192 | | /// serializing and deserializing ECDSA signatures using the `Serialize` and |
193 | | /// `Deserialize` traits. |
194 | | /// |
195 | | /// The serialization uses a hexadecimal encoding when used with |
196 | | /// "human readable" text formats, and a binary encoding otherwise. |
197 | | #[derive(Clone, Eq, PartialEq)] |
198 | | pub struct Signature<C: PrimeCurve> { |
199 | | r: ScalarPrimitive<C>, |
200 | | s: ScalarPrimitive<C>, |
201 | | } |
202 | | |
203 | | impl<C> Signature<C> |
204 | | where |
205 | | C: PrimeCurve, |
206 | | SignatureSize<C>: ArrayLength<u8>, |
207 | | { |
208 | | /// Parse a signature from fixed-width bytes, i.e. 2 * the size of |
209 | | /// [`FieldBytes`] for a particular curve. |
210 | | /// |
211 | | /// # Returns |
212 | | /// - `Ok(signature)` if the `r` and `s` components are both in the valid |
213 | | /// range `1..n` when serialized as concatenated big endian integers. |
214 | | /// - `Err(err)` if the `r` and/or `s` component of the signature is |
215 | | /// out-of-range when interpreted as a big endian integer. |
216 | 0 | pub fn from_bytes(bytes: &SignatureBytes<C>) -> Result<Self> { |
217 | 0 | let (r_bytes, s_bytes) = bytes.split_at(C::FieldBytesSize::USIZE); |
218 | 0 | let r = FieldBytes::<C>::clone_from_slice(r_bytes); |
219 | 0 | let s = FieldBytes::<C>::clone_from_slice(s_bytes); |
220 | 0 | Self::from_scalars(r, s) |
221 | 0 | } |
222 | | |
223 | | /// Parse a signature from a byte slice. |
224 | 0 | pub fn from_slice(slice: &[u8]) -> Result<Self> { |
225 | 0 | if slice.len() == SignatureSize::<C>::USIZE { |
226 | 0 | Self::from_bytes(SignatureBytes::<C>::from_slice(slice)) |
227 | | } else { |
228 | 0 | Err(Error::new()) |
229 | | } |
230 | 0 | } |
231 | | |
232 | | /// Parse a signature from ASN.1 DER. |
233 | | #[cfg(feature = "der")] |
234 | 0 | pub fn from_der(bytes: &[u8]) -> Result<Self> |
235 | 0 | where |
236 | 0 | der::MaxSize<C>: ArrayLength<u8>, |
237 | 0 | <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, |
238 | | { |
239 | 0 | der::Signature::<C>::try_from(bytes).and_then(Self::try_from) |
240 | 0 | } |
241 | | |
242 | | /// Create a [`Signature`] from the serialized `r` and `s` scalar values |
243 | | /// which comprise the signature. |
244 | | /// |
245 | | /// # Returns |
246 | | /// - `Ok(signature)` if the `r` and `s` components are both in the valid |
247 | | /// range `1..n` when serialized as concatenated big endian integers. |
248 | | /// - `Err(err)` if the `r` and/or `s` component of the signature is |
249 | | /// out-of-range when interpreted as a big endian integer. |
250 | 2.89k | pub fn from_scalars(r: impl Into<FieldBytes<C>>, s: impl Into<FieldBytes<C>>) -> Result<Self> { |
251 | 2.89k | let r = ScalarPrimitive::from_slice(&r.into()).map_err(|_| Error::new())?; Unexecuted instantiation: <ecdsa::Signature<p256::NistP256>>::from_scalars::<p256::arithmetic::scalar::Scalar, p256::arithmetic::scalar::Scalar>::{closure#0}Unexecuted instantiation: <ecdsa::Signature<_>>::from_scalars::<_, _>::{closure#0} |
252 | 2.89k | let s = ScalarPrimitive::from_slice(&s.into()).map_err(|_| Error::new())?; Unexecuted instantiation: <ecdsa::Signature<p256::NistP256>>::from_scalars::<p256::arithmetic::scalar::Scalar, p256::arithmetic::scalar::Scalar>::{closure#1}Unexecuted instantiation: <ecdsa::Signature<_>>::from_scalars::<_, _>::{closure#1} |
253 | | |
254 | 2.89k | if r.is_zero().into() || s.is_zero().into() { |
255 | 0 | return Err(Error::new()); |
256 | 2.89k | } |
257 | | |
258 | 2.89k | Ok(Self { r, s }) |
259 | 2.89k | } <ecdsa::Signature<p256::NistP256>>::from_scalars::<p256::arithmetic::scalar::Scalar, p256::arithmetic::scalar::Scalar> Line | Count | Source | 250 | 2.89k | pub fn from_scalars(r: impl Into<FieldBytes<C>>, s: impl Into<FieldBytes<C>>) -> Result<Self> { | 251 | 2.89k | let r = ScalarPrimitive::from_slice(&r.into()).map_err(|_| Error::new())?; | 252 | 2.89k | let s = ScalarPrimitive::from_slice(&s.into()).map_err(|_| Error::new())?; | 253 | | | 254 | 2.89k | if r.is_zero().into() || s.is_zero().into() { | 255 | 0 | return Err(Error::new()); | 256 | 2.89k | } | 257 | | | 258 | 2.89k | Ok(Self { r, s }) | 259 | 2.89k | } |
Unexecuted instantiation: <ecdsa::Signature<_>>::from_scalars::<_, _> |
260 | | |
261 | | /// Split the signature into its `r` and `s` components, represented as bytes. |
262 | 2.89k | pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) { |
263 | 2.89k | (self.r.to_bytes(), self.s.to_bytes()) |
264 | 2.89k | } <ecdsa::Signature<p256::NistP256>>::split_bytes Line | Count | Source | 262 | 2.89k | pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) { | 263 | 2.89k | (self.r.to_bytes(), self.s.to_bytes()) | 264 | 2.89k | } |
Unexecuted instantiation: <ecdsa::Signature<_>>::split_bytes |
265 | | |
266 | | /// Serialize this signature as bytes. |
267 | 0 | pub fn to_bytes(&self) -> SignatureBytes<C> { |
268 | 0 | let mut bytes = SignatureBytes::<C>::default(); |
269 | 0 | let (r_bytes, s_bytes) = bytes.split_at_mut(C::FieldBytesSize::USIZE); |
270 | 0 | r_bytes.copy_from_slice(&self.r.to_bytes()); |
271 | 0 | s_bytes.copy_from_slice(&self.s.to_bytes()); |
272 | 0 | bytes |
273 | 0 | } |
274 | | |
275 | | /// Serialize this signature as ASN.1 DER. |
276 | | #[cfg(feature = "der")] |
277 | 2.89k | pub fn to_der(&self) -> der::Signature<C> |
278 | 2.89k | where |
279 | 2.89k | der::MaxSize<C>: ArrayLength<u8>, |
280 | 2.89k | <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, |
281 | | { |
282 | 2.89k | let (r, s) = self.split_bytes(); |
283 | 2.89k | der::Signature::from_components(&r, &s).expect("DER encoding error") |
284 | 2.89k | } <ecdsa::Signature<p256::NistP256>>::to_der Line | Count | Source | 277 | 2.89k | pub fn to_der(&self) -> der::Signature<C> | 278 | 2.89k | where | 279 | 2.89k | der::MaxSize<C>: ArrayLength<u8>, | 280 | 2.89k | <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, | 281 | | { | 282 | 2.89k | let (r, s) = self.split_bytes(); | 283 | 2.89k | der::Signature::from_components(&r, &s).expect("DER encoding error") | 284 | 2.89k | } |
Unexecuted instantiation: <ecdsa::Signature<_>>::to_der |
285 | | |
286 | | /// Convert this signature into a byte vector. |
287 | | #[cfg(feature = "alloc")] |
288 | 0 | pub fn to_vec(&self) -> Vec<u8> { |
289 | 0 | self.to_bytes().to_vec() |
290 | 0 | } |
291 | | } |
292 | | |
293 | | #[cfg(feature = "arithmetic")] |
294 | | impl<C> Signature<C> |
295 | | where |
296 | | C: PrimeCurve + CurveArithmetic, |
297 | | SignatureSize<C>: ArrayLength<u8>, |
298 | | { |
299 | | /// Get the `r` component of this signature |
300 | 0 | pub fn r(&self) -> NonZeroScalar<C> { |
301 | 0 | NonZeroScalar::new(self.r.into()).unwrap() |
302 | 0 | } |
303 | | |
304 | | /// Get the `s` component of this signature |
305 | 0 | pub fn s(&self) -> NonZeroScalar<C> { |
306 | 0 | NonZeroScalar::new(self.s.into()).unwrap() |
307 | 0 | } |
308 | | |
309 | | /// Split the signature into its `r` and `s` scalars. |
310 | 0 | pub fn split_scalars(&self) -> (NonZeroScalar<C>, NonZeroScalar<C>) { |
311 | 0 | (self.r(), self.s()) |
312 | 0 | } |
313 | | |
314 | | /// Normalize signature into "low S" form as described in |
315 | | /// [BIP 0062: Dealing with Malleability][1]. |
316 | | /// |
317 | | /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki |
318 | 0 | pub fn normalize_s(&self) -> Option<Self> { |
319 | 0 | let s = self.s(); |
320 | | |
321 | 0 | if s.is_high().into() { |
322 | 0 | let mut result = self.clone(); |
323 | 0 | result.s = ScalarPrimitive::from(-s); |
324 | 0 | Some(result) |
325 | | } else { |
326 | 0 | None |
327 | | } |
328 | 0 | } |
329 | | } |
330 | | |
331 | | impl<C> Copy for Signature<C> |
332 | | where |
333 | | C: PrimeCurve, |
334 | | SignatureSize<C>: ArrayLength<u8>, |
335 | | <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy, |
336 | | { |
337 | | } |
338 | | |
339 | | impl<C> From<Signature<C>> for SignatureBytes<C> |
340 | | where |
341 | | C: PrimeCurve, |
342 | | SignatureSize<C>: ArrayLength<u8>, |
343 | | { |
344 | 0 | fn from(signature: Signature<C>) -> SignatureBytes<C> { |
345 | 0 | signature.to_bytes() |
346 | 0 | } |
347 | | } |
348 | | |
349 | | impl<C> SignatureEncoding for Signature<C> |
350 | | where |
351 | | C: PrimeCurve, |
352 | | SignatureSize<C>: ArrayLength<u8>, |
353 | | { |
354 | | type Repr = SignatureBytes<C>; |
355 | | } |
356 | | |
357 | | impl<C> TryFrom<&[u8]> for Signature<C> |
358 | | where |
359 | | C: PrimeCurve, |
360 | | SignatureSize<C>: ArrayLength<u8>, |
361 | | { |
362 | | type Error = Error; |
363 | | |
364 | 0 | fn try_from(slice: &[u8]) -> Result<Self> { |
365 | 0 | Self::from_slice(slice) |
366 | 0 | } |
367 | | } |
368 | | |
369 | | impl<C> fmt::Debug for Signature<C> |
370 | | where |
371 | | C: PrimeCurve, |
372 | | SignatureSize<C>: ArrayLength<u8>, |
373 | | { |
374 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
375 | 0 | write!(f, "ecdsa::Signature<{:?}>(", C::default())?; |
376 | | |
377 | 0 | for byte in self.to_bytes() { |
378 | 0 | write!(f, "{:02X}", byte)?; |
379 | | } |
380 | | |
381 | 0 | write!(f, ")") |
382 | 0 | } |
383 | | } |
384 | | |
385 | | impl<C> fmt::Display for Signature<C> |
386 | | where |
387 | | C: PrimeCurve, |
388 | | SignatureSize<C>: ArrayLength<u8>, |
389 | | { |
390 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
391 | 0 | write!(f, "{:X}", self) |
392 | 0 | } |
393 | | } |
394 | | |
395 | | impl<C> fmt::LowerHex for Signature<C> |
396 | | where |
397 | | C: PrimeCurve, |
398 | | SignatureSize<C>: ArrayLength<u8>, |
399 | | { |
400 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
401 | 0 | for byte in self.to_bytes() { |
402 | 0 | write!(f, "{:02x}", byte)?; |
403 | | } |
404 | 0 | Ok(()) |
405 | 0 | } |
406 | | } |
407 | | |
408 | | impl<C> fmt::UpperHex for Signature<C> |
409 | | where |
410 | | C: PrimeCurve, |
411 | | SignatureSize<C>: ArrayLength<u8>, |
412 | | { |
413 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
414 | 0 | for byte in self.to_bytes() { |
415 | 0 | write!(f, "{:02X}", byte)?; |
416 | | } |
417 | 0 | Ok(()) |
418 | 0 | } |
419 | | } |
420 | | |
421 | | #[cfg(feature = "arithmetic")] |
422 | | impl<C> str::FromStr for Signature<C> |
423 | | where |
424 | | C: PrimeCurve + CurveArithmetic, |
425 | | SignatureSize<C>: ArrayLength<u8>, |
426 | | { |
427 | | type Err = Error; |
428 | | |
429 | 0 | fn from_str(hex: &str) -> Result<Self> { |
430 | 0 | if hex.as_bytes().len() != C::FieldBytesSize::USIZE * 4 { |
431 | 0 | return Err(Error::new()); |
432 | 0 | } |
433 | | |
434 | | // This check is mainly to ensure `hex.split_at` below won't panic |
435 | 0 | if !hex |
436 | 0 | .as_bytes() |
437 | 0 | .iter() |
438 | 0 | .all(|&byte| matches!(byte, b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z')) |
439 | | { |
440 | 0 | return Err(Error::new()); |
441 | 0 | } |
442 | | |
443 | 0 | let (r_hex, s_hex) = hex.split_at(C::FieldBytesSize::USIZE * 2); |
444 | | |
445 | 0 | let r = r_hex |
446 | 0 | .parse::<NonZeroScalar<C>>() |
447 | 0 | .map_err(|_| Error::new())?; |
448 | | |
449 | 0 | let s = s_hex |
450 | 0 | .parse::<NonZeroScalar<C>>() |
451 | 0 | .map_err(|_| Error::new())?; |
452 | | |
453 | 0 | Self::from_scalars(r, s) |
454 | 0 | } |
455 | | } |
456 | | |
457 | | /// ECDSA [`ObjectIdentifier`] which identifies the digest used by default |
458 | | /// with the `Signer` and `Verifier` traits. |
459 | | /// |
460 | | /// To support non-default digest algorithms, use the [`SignatureWithOid`] |
461 | | /// type instead. |
462 | | #[cfg(all(feature = "digest", feature = "hazmat"))] |
463 | | impl<C> AssociatedOid for Signature<C> |
464 | | where |
465 | | C: hazmat::DigestPrimitive, |
466 | | C::Digest: AssociatedOid, |
467 | | { |
468 | | const OID: ObjectIdentifier = match ecdsa_oid_for_digest(C::Digest::OID) { |
469 | | Some(oid) => oid, |
470 | | None => panic!("no RFC5758 ECDSA OID defined for DigestPrimitive::Digest"), |
471 | | }; |
472 | | } |
473 | | |
474 | | /// ECDSA `AlgorithmIdentifier` which identifies the digest used by default |
475 | | /// with the `Signer` and `Verifier` traits. |
476 | | #[cfg(feature = "pkcs8")] |
477 | | impl<C> AssociatedAlgorithmIdentifier for Signature<C> |
478 | | where |
479 | | C: PrimeCurve, |
480 | | Self: AssociatedOid, |
481 | | { |
482 | | type Params = AnyRef<'static>; |
483 | | |
484 | | const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef { |
485 | | oid: Self::OID, |
486 | | parameters: None, |
487 | | }; |
488 | | } |
489 | | |
490 | | #[cfg(feature = "serde")] |
491 | | impl<C> Serialize for Signature<C> |
492 | | where |
493 | | C: PrimeCurve, |
494 | | SignatureSize<C>: ArrayLength<u8>, |
495 | | { |
496 | | fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> |
497 | | where |
498 | | S: ser::Serializer, |
499 | | { |
500 | | serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) |
501 | | } |
502 | | } |
503 | | |
504 | | #[cfg(feature = "serde")] |
505 | | impl<'de, C> Deserialize<'de> for Signature<C> |
506 | | where |
507 | | C: PrimeCurve, |
508 | | SignatureSize<C>: ArrayLength<u8>, |
509 | | { |
510 | | fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> |
511 | | where |
512 | | D: de::Deserializer<'de>, |
513 | | { |
514 | | let mut bytes = SignatureBytes::<C>::default(); |
515 | | serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; |
516 | | Self::try_from(bytes.as_slice()).map_err(de::Error::custom) |
517 | | } |
518 | | } |
519 | | |
520 | | /// An extended [`Signature`] type which is parameterized by an |
521 | | /// `ObjectIdentifier` which identifies the ECDSA variant used by a |
522 | | /// particular signature. |
523 | | /// |
524 | | /// Valid `ObjectIdentifiers` are defined in [RFC5758 § 3.2]: |
525 | | /// |
526 | | /// - SHA-224: [`ECDSA_SHA224_OID`] (1.2.840.10045.4.3.1) |
527 | | /// - SHA-256: [`ECDSA_SHA256_OID`] (1.2.840.10045.4.3.2) |
528 | | /// - SHA-384: [`ECDSA_SHA384_OID`] (1.2.840.10045.4.3.3) |
529 | | /// - SHA-512: [`ECDSA_SHA512_OID`] (1.2.840.10045.4.3.4) |
530 | | /// |
531 | | /// [RFC5758 § 3.2]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 |
532 | | #[cfg(feature = "digest")] |
533 | | #[derive(Clone, Eq, PartialEq)] |
534 | | pub struct SignatureWithOid<C: PrimeCurve> { |
535 | | /// Inner signature type. |
536 | | signature: Signature<C>, |
537 | | |
538 | | /// OID which identifies the ECDSA variant used. |
539 | | /// |
540 | | /// MUST be one of the ECDSA algorithm variants as defined in RFC5758. |
541 | | /// |
542 | | /// These OIDs begin with `1.2.840.10045.4`. |
543 | | oid: ObjectIdentifier, |
544 | | } |
545 | | |
546 | | #[cfg(feature = "digest")] |
547 | | impl<C> SignatureWithOid<C> |
548 | | where |
549 | | C: PrimeCurve, |
550 | | { |
551 | | /// Create a new signature with an explicitly provided OID. |
552 | | /// |
553 | | /// OID must begin with `1.2.840.10045.4`, the [RFC5758] OID prefix for |
554 | | /// ECDSA variants. |
555 | | /// |
556 | | /// [RFC5758]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 |
557 | 0 | pub fn new(signature: Signature<C>, oid: ObjectIdentifier) -> Result<Self> { |
558 | | // TODO(tarcieri): use `ObjectIdentifier::starts_with` |
559 | 0 | for (arc1, arc2) in ObjectIdentifier::new_unwrap("1.2.840.10045.4.3") |
560 | 0 | .arcs() |
561 | 0 | .zip(oid.arcs()) |
562 | | { |
563 | 0 | if arc1 != arc2 { |
564 | 0 | return Err(Error::new()); |
565 | 0 | } |
566 | | } |
567 | | |
568 | 0 | Ok(Self { signature, oid }) |
569 | 0 | } |
570 | | |
571 | | /// Create a new signature, determining the OID from the given digest. |
572 | | /// |
573 | | /// Supports SHA-2 family digests as enumerated in [RFC5758 § 3.2], i.e. |
574 | | /// SHA-224, SHA-256, SHA-384, or SHA-512. |
575 | | /// |
576 | | /// [RFC5758 § 3.2]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 |
577 | 0 | pub fn new_with_digest<D>(signature: Signature<C>) -> Result<Self> |
578 | 0 | where |
579 | 0 | D: AssociatedOid + Digest, |
580 | | { |
581 | 0 | let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?; |
582 | 0 | Ok(Self { signature, oid }) |
583 | 0 | } |
584 | | |
585 | | /// Parse a signature from fixed-with bytes. |
586 | 0 | pub fn from_bytes_with_digest<D>(bytes: &SignatureBytes<C>) -> Result<Self> |
587 | 0 | where |
588 | 0 | D: AssociatedOid + Digest, |
589 | 0 | SignatureSize<C>: ArrayLength<u8>, |
590 | | { |
591 | 0 | Self::new_with_digest::<D>(Signature::<C>::from_bytes(bytes)?) |
592 | 0 | } |
593 | | |
594 | | /// Parse a signature from a byte slice. |
595 | 0 | pub fn from_slice_with_digest<D>(slice: &[u8]) -> Result<Self> |
596 | 0 | where |
597 | 0 | D: AssociatedOid + Digest, |
598 | 0 | SignatureSize<C>: ArrayLength<u8>, |
599 | | { |
600 | 0 | Self::new_with_digest::<D>(Signature::<C>::from_slice(slice)?) |
601 | 0 | } |
602 | | |
603 | | /// Get the fixed-width ECDSA signature. |
604 | 0 | pub fn signature(&self) -> &Signature<C> { |
605 | 0 | &self.signature |
606 | 0 | } |
607 | | |
608 | | /// Get the ECDSA OID for this signature. |
609 | 0 | pub fn oid(&self) -> ObjectIdentifier { |
610 | 0 | self.oid |
611 | 0 | } |
612 | | |
613 | | /// Serialize this signature as bytes. |
614 | 0 | pub fn to_bytes(&self) -> SignatureBytes<C> |
615 | 0 | where |
616 | 0 | SignatureSize<C>: ArrayLength<u8>, |
617 | | { |
618 | 0 | self.signature.to_bytes() |
619 | 0 | } |
620 | | } |
621 | | |
622 | | #[cfg(feature = "digest")] |
623 | | impl<C> Copy for SignatureWithOid<C> |
624 | | where |
625 | | C: PrimeCurve, |
626 | | SignatureSize<C>: ArrayLength<u8>, |
627 | | <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy, |
628 | | { |
629 | | } |
630 | | |
631 | | #[cfg(feature = "digest")] |
632 | | impl<C> From<SignatureWithOid<C>> for Signature<C> |
633 | | where |
634 | | C: PrimeCurve, |
635 | | { |
636 | 0 | fn from(sig: SignatureWithOid<C>) -> Signature<C> { |
637 | 0 | sig.signature |
638 | 0 | } |
639 | | } |
640 | | |
641 | | #[cfg(feature = "digest")] |
642 | | impl<C> From<SignatureWithOid<C>> for SignatureBytes<C> |
643 | | where |
644 | | C: PrimeCurve, |
645 | | SignatureSize<C>: ArrayLength<u8>, |
646 | | { |
647 | 0 | fn from(signature: SignatureWithOid<C>) -> SignatureBytes<C> { |
648 | 0 | signature.to_bytes() |
649 | 0 | } |
650 | | } |
651 | | |
652 | | /// NOTE: this implementation assumes the default digest for the given elliptic |
653 | | /// curve as defined by [`hazmat::DigestPrimitive`]. |
654 | | /// |
655 | | /// When working with alternative digests, you will need to use e.g. |
656 | | /// [`SignatureWithOid::new_with_digest`]. |
657 | | #[cfg(all(feature = "digest", feature = "hazmat"))] |
658 | | impl<C> SignatureEncoding for SignatureWithOid<C> |
659 | | where |
660 | | C: hazmat::DigestPrimitive, |
661 | | C::Digest: AssociatedOid, |
662 | | SignatureSize<C>: ArrayLength<u8>, |
663 | | { |
664 | | type Repr = SignatureBytes<C>; |
665 | | } |
666 | | |
667 | | /// NOTE: this implementation assumes the default digest for the given elliptic |
668 | | /// curve as defined by [`hazmat::DigestPrimitive`]. |
669 | | /// |
670 | | /// When working with alternative digests, you will need to use e.g. |
671 | | /// [`SignatureWithOid::new_with_digest`]. |
672 | | #[cfg(all(feature = "digest", feature = "hazmat"))] |
673 | | impl<C> TryFrom<&[u8]> for SignatureWithOid<C> |
674 | | where |
675 | | C: hazmat::DigestPrimitive, |
676 | | C::Digest: AssociatedOid, |
677 | | SignatureSize<C>: ArrayLength<u8>, |
678 | | { |
679 | | type Error = Error; |
680 | | |
681 | 0 | fn try_from(slice: &[u8]) -> Result<Self> { |
682 | 0 | Self::new(Signature::<C>::from_slice(slice)?, C::Digest::OID) |
683 | 0 | } |
684 | | } |
685 | | |
686 | | #[cfg(all(feature = "alloc", feature = "pkcs8"))] |
687 | | impl<C> DynAssociatedAlgorithmIdentifier for SignatureWithOid<C> |
688 | | where |
689 | | C: PrimeCurve, |
690 | | { |
691 | | fn algorithm_identifier(&self) -> spki::Result<AlgorithmIdentifierOwned> { |
692 | | Ok(AlgorithmIdentifierOwned { |
693 | | oid: self.oid, |
694 | | parameters: None, |
695 | | }) |
696 | | } |
697 | | } |
698 | | |
699 | | /// Get the ECDSA OID for a given digest OID. |
700 | | #[cfg(feature = "digest")] |
701 | 0 | const fn ecdsa_oid_for_digest(digest_oid: ObjectIdentifier) -> Option<ObjectIdentifier> { |
702 | 0 | match digest_oid { |
703 | 0 | SHA224_OID => Some(ECDSA_SHA224_OID), |
704 | 0 | SHA256_OID => Some(ECDSA_SHA256_OID), |
705 | 0 | SHA384_OID => Some(ECDSA_SHA384_OID), |
706 | 0 | SHA512_OID => Some(ECDSA_SHA512_OID), |
707 | 0 | _ => None, |
708 | | } |
709 | 0 | } |