diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/ecdsa | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ecdsa')
-rw-r--r-- | vendor/ecdsa/.cargo-checksum.json | 2 | ||||
-rw-r--r-- | vendor/ecdsa/CHANGELOG.md | 97 | ||||
-rw-r--r-- | vendor/ecdsa/Cargo.toml | 50 | ||||
-rw-r--r-- | vendor/ecdsa/README.md | 4 | ||||
-rw-r--r-- | vendor/ecdsa/src/der.rs | 240 | ||||
-rw-r--r-- | vendor/ecdsa/src/dev.rs | 33 | ||||
-rw-r--r-- | vendor/ecdsa/src/hazmat.rs | 235 | ||||
-rw-r--r-- | vendor/ecdsa/src/lib.rs | 467 | ||||
-rw-r--r-- | vendor/ecdsa/src/recovery.rs | 247 | ||||
-rw-r--r-- | vendor/ecdsa/src/sign.rs | 424 | ||||
-rw-r--r-- | vendor/ecdsa/src/signing.rs | 598 | ||||
-rw-r--r-- | vendor/ecdsa/src/verify.rs | 325 | ||||
-rw-r--r-- | vendor/ecdsa/src/verifying.rs | 482 |
13 files changed, 2149 insertions, 1055 deletions
diff --git a/vendor/ecdsa/.cargo-checksum.json b/vendor/ecdsa/.cargo-checksum.json index 3f233a5f2..10d399ee2 100644 --- a/vendor/ecdsa/.cargo-checksum.json +++ b/vendor/ecdsa/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"3ce4bb9d644207d6be3015fb14fb8b21b5a5b1726d6e23e518069c09b72c3c6d","Cargo.toml":"8251cd573e1cccd72cc28d182555834efeced8c9b9b9d8b6f66dc45e66d7c88c","LICENSE-APACHE":"78779d420019e6b4630376af8e86b6b335ee8a2f89ede6e0411e0469a326aaa4","LICENSE-MIT":"bdebaf9156a298f8fdab56dd26cb5144673de522d80f4c0d88e0039145f147f9","README.md":"5b6363fc1dc18b5ea22dcb4e11481abd2c9fff9a5bce268296e119dc23cdc3d6","src/der.rs":"496d7b6047b4d346fa76c00b07db2cec06d935e552ced3abb939ea2a84a38c38","src/dev.rs":"2403e76837802f1587ea9b7da7ce62f6ae65b431691977f31bce71ae36639a05","src/hazmat.rs":"7baab4647e5e9fb2d918c69a8df557aef41e4b5cc92fc964592f315798603e40","src/lib.rs":"8a9f7e22c1ffe206eaaf0844ca4eaea29910f7cfd6dd61e3c95b1297c01931b0","src/recovery.rs":"7dd92127de3b33883ca1bf1eaadd4ce8176febe9b5c1353dc31fbee0c092a611","src/sign.rs":"6c360d0292e23c21dc5274a08ab98c5005df4b83a8d22871cfc91d4c413b0511","src/verify.rs":"19a759a7a8db7e0b17cbf6ba69a8fe2634089546b31a6423d86f8b693a6f1d7d","tests/lib.rs":"68922b3fb793f7f64a6fdf8aa59b6fb9432d4706d7ad1d82129a8337c5cf6568"},"package":"413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"}
\ No newline at end of file +{"files":{"CHANGELOG.md":"3b692c15478b5aa15df17a094b84b03e0cfb6c56dbe8a5ec6d40b53ef1dcea2f","Cargo.toml":"09391aecb7abdf0ec8a55d81dad7f5df355562b286d2aca24b764243a8e06453","LICENSE-APACHE":"78779d420019e6b4630376af8e86b6b335ee8a2f89ede6e0411e0469a326aaa4","LICENSE-MIT":"bdebaf9156a298f8fdab56dd26cb5144673de522d80f4c0d88e0039145f147f9","README.md":"f99485065d3d5541ef1814ea8d3f75718f08cb78eb5626f9d34941799655b4b9","src/der.rs":"d3320fc6c6c3e5f08c8323c07bdf774a2f4cfc97d8951751c7e89232572167a7","src/dev.rs":"75d56ac79f04efc018b37eca752c7861579772a758cac94874ccf85aa880602a","src/hazmat.rs":"6d888d3389ac9d0431beed24b865260f0554271cdbb9aa24a6ca9341717fdfc7","src/lib.rs":"63f4d7ead0024b1fba3083c413a21e168d435d0917208be61c9fad868c84acdc","src/recovery.rs":"41141f9f4ffbd155c5167fbe749299496077c55e6b64ed83f65ced1372205623","src/signing.rs":"11842af046b43fe53add72a7fdc78a9555a1dbc37fe6bb0d1139e8b25491538f","src/verifying.rs":"c7441025d4ddcfce2c7701813d84c032364da4bd38bd28895a75d09eaca53ee3","tests/lib.rs":"68922b3fb793f7f64a6fdf8aa59b6fb9432d4706d7ad1d82129a8337c5cf6568"},"package":"a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd"}
\ No newline at end of file diff --git a/vendor/ecdsa/CHANGELOG.md b/vendor/ecdsa/CHANGELOG.md index ba65d59cf..c551aaa8d 100644 --- a/vendor/ecdsa/CHANGELOG.md +++ b/vendor/ecdsa/CHANGELOG.md @@ -4,6 +4,103 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.16.6 (2023-04-09) +### Fixed +- Test macro handling of serialized field size ([#707]) + +[#707]: https://github.com/RustCrypto/signatures/pull/707 + +## 0.16.5 (2023-04-08) +### Fixed +- Use `C::FieldBytesSize` instead of `C::Uint::BYTES` ([#705]) + +[#705]: https://github.com/RustCrypto/signatures/pull/705 + +## 0.16.4 (2023-04-05) +### Fixed +- `RecoveryId` computation in `SignPrimitive` ([#702]) + +[#702]: https://github.com/RustCrypto/signatures/pull/702 + +## 0.16.3 (2023-04-04) +### Added +- RFC5758 OID support ([#686]) +- `SignatureAlgorithmIdentifier` impls for `SigningKey`/`VerifyingKey` ([#688]) +- `SignatureWithOid` ([#689], [#690]) +- `AssociatedAlgorithmIdentifier` impls for `SigningKey`/`VerifyingKey` ([#698]) + +### Changed +- Loosen `signature` bound to `2.0, <2.2` ([#697]) + +[#686]: https://github.com/RustCrypto/signatures/pull/686 +[#688]: https://github.com/RustCrypto/signatures/pull/688 +[#689]: https://github.com/RustCrypto/signatures/pull/689 +[#690]: https://github.com/RustCrypto/signatures/pull/690 +[#697]: https://github.com/RustCrypto/signatures/pull/697 +[#698]: https://github.com/RustCrypto/signatures/pull/698 + +## 0.16.2 (2023-03-28) +### Added +- Handle the reduced R.x case in public key recovery ([#680]) +- `Signature::{from_bytes, from_slice}` methods ([#684]) + +[#680]: https://github.com/RustCrypto/signatures/pull/680 +[#684]: https://github.com/RustCrypto/signatures/pull/684 + +## 0.16.1 (2023-03-09) +### Added +- `VerifyingKey::to_sec1_bytes` + more conversions ([#675]) + +[#675]: https://github.com/RustCrypto/signatures/pull/675 + +## 0.16.0 (2023-03-01) +### Added +- `Decode` and `Encode` impls for `der::Signature` ([#666]) + +### Changed +- Use `Scalar::invert_vartime` for faster verification ([#651]) +- Bump `serdect` dependency to 0.2 ([#657]) +- Bump `elliptic-curve` dependency to v0.13; MSRV 1.65 ([#660], [#663]) +- Bump `rfc6979` dependency to v0.4 ([#662]) + +[#651]: https://github.com/RustCrypto/signatures/pull/651 +[#657]: https://github.com/RustCrypto/signatures/pull/657 +[#660]: https://github.com/RustCrypto/signatures/pull/660 +[#662]: https://github.com/RustCrypto/signatures/pull/662 +[#666]: https://github.com/RustCrypto/signatures/pull/666 + +## 0.15.1 (2023-01-23) +### Added +- `SigningKey::*_recoverable` methods ([#635]) + +[#635]: https://github.com/RustCrypto/signatures/pull/635 + +## 0.15.0 (2023-01-15) +### Added +- `DigestPrimitive::Digest` now has bounds that work with RFC6979 ([#568]) +- `*Signer`/`*Verifier` impls for `der::Signature` ([#569]) +- `VerifyingKey` recovery support ([#576]) +- Trial recovery support ([#580]) + +### Changed +- Signature now internally structured with `r` and `s` components ([#565]) +- `SigningKey::verifying_key` now returns a reference ([#567]) +- Refactor `prehash_to_field_bytes` to `bits2field` free function ([#574]) +- Rename `sign` feature to `signing` ([#610]) +- Rename `verify` feature to `verifying` features ([#610]) +- Bump `signature` crate dependency to v2.0 ([#614]) + +[#565]: https://github.com/RustCrypto/signatures/pull/565 +[#567]: https://github.com/RustCrypto/signatures/pull/567 +[#574]: https://github.com/RustCrypto/signatures/pull/574 +[#580]: https://github.com/RustCrypto/signatures/pull/580 +[#568]: https://github.com/RustCrypto/signatures/pull/568 +[#569]: https://github.com/RustCrypto/signatures/pull/569 +[#576]: https://github.com/RustCrypto/signatures/pull/576 +[#580]: https://github.com/RustCrypto/signatures/pull/580 +[#610]: https://github.com/RustCrypto/signatures/pull/610 +[#614]: https://github.com/RustCrypto/signatures/pull/614 + ## 0.14.8 (2022-09-27) ### Added - Impl `From<SigningKey>` for `SecretKey` ([#548]) diff --git a/vendor/ecdsa/Cargo.toml b/vendor/ecdsa/Cargo.toml index 62a5410a5..5f0e94d97 100644 --- a/vendor/ecdsa/Cargo.toml +++ b/vendor/ecdsa/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.57" +rust-version = "1.65" name = "ecdsa" -version = "0.14.8" +version = "0.16.6" authors = ["RustCrypto Developers"] description = """ Pure Rust implementation of the Elliptic Curve Digital Signature Algorithm @@ -43,11 +43,17 @@ rustdoc-args = [ ] [dependencies.der] -version = "0.6" +version = "0.7" optional = true +[dependencies.digest] +version = "0.10.6" +features = ["oid"] +optional = true +default-features = false + [dependencies.elliptic-curve] -version = "0.12" +version = "0.13.3" features = [ "digest", "sec1", @@ -55,37 +61,43 @@ features = [ default-features = false [dependencies.rfc6979] -version = "0.3" +version = "0.4" optional = true [dependencies.serdect] -version = "0.1" +version = "0.2" features = ["alloc"] optional = true default-features = false +[dependencies.sha2] +version = "0.10" +features = ["oid"] +optional = true +default-features = false + [dependencies.signature] -version = ">=1.6.2, <1.7" -features = [ - "hazmat-preview", - "rand-preview", -] +version = "2.0, <2.2" +features = ["rand_core"] default-features = false [dev-dependencies.elliptic-curve] -version = "0.12" +version = "0.13" features = ["dev"] default-features = false [dev-dependencies.hex-literal] -version = "0.3" +version = "0.4" [dev-dependencies.sha2] version = "0.10" default-features = false [features] -alloc = [] +alloc = [ + "elliptic-curve/alloc", + "signature/alloc", +] arithmetic = ["elliptic-curve/arithmetic"] default = ["digest"] dev = [ @@ -94,13 +106,17 @@ dev = [ "elliptic-curve/dev", "hazmat", ] -digest = ["signature/digest-preview"] +digest = [ + "dep:digest", + "signature/digest", +] hazmat = [] pem = [ "elliptic-curve/pem", "pkcs8", ] pkcs8 = [ + "digest", "elliptic-curve/pkcs8", "der", ] @@ -108,7 +124,7 @@ serde = [ "elliptic-curve/serde", "serdect", ] -sign = [ +signing = [ "arithmetic", "digest", "hazmat", @@ -119,7 +135,7 @@ std = [ "elliptic-curve/std", "signature/std", ] -verify = [ +verifying = [ "arithmetic", "digest", "hazmat", diff --git a/vendor/ecdsa/README.md b/vendor/ecdsa/README.md index 6da609998..06ed0dc37 100644 --- a/vendor/ecdsa/README.md +++ b/vendor/ecdsa/README.md @@ -41,7 +41,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -This crate requires **Rust 1.57** at a minimum. +This crate requires **Rust 1.65** at a minimum. We may change the MSRV in the future, but it will be accompanied by a minor version bump. @@ -70,7 +70,7 @@ dual licensed as above, without any additional terms or conditions. [build-image]: https://github.com/RustCrypto/signatures/actions/workflows/ecdsa.yml/badge.svg [build-link]: https://github.com/RustCrypto/signatures/actions/workflows/ecdsa.yml [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260048-signatures diff --git a/vendor/ecdsa/src/der.rs b/vendor/ecdsa/src/der.rs index 5925df443..cb774232e 100644 --- a/vendor/ecdsa/src/der.rs +++ b/vendor/ecdsa/src/der.rs @@ -2,19 +2,21 @@ use crate::{Error, Result}; use core::{ - fmt, + 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::Encoding as _, consts::U9, - generic_array::{ArrayLength, GenericArray}, - FieldSize, PrimeCurve, + generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, + FieldBytesSize, PrimeCurve, }; #[cfg(feature = "alloc")] -use alloc::boxed::Box; +use { + alloc::{boxed::Box, vec::Vec}, + signature::SignatureEncoding, +}; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; @@ -36,7 +38,7 @@ use serdect::serde::{de, ser, Deserialize, Serialize}; pub type MaxOverhead = U9; /// Maximum size of an ASN.1 DER encoded signature for the given elliptic curve. -pub type MaxSize<C> = <<FieldSize<C> as Add>::Output as Add<MaxOverhead>>::Output; +pub type MaxSize<C> = <<FieldBytesSize<C> as Add>::Output as Add<MaxOverhead>>::Output; /// Byte array containing a serialized ASN.1 signature type SignatureBytes<C> = GenericArray<u8, MaxSize<C>>; @@ -48,7 +50,7 @@ pub struct Signature<C> where C: PrimeCurve, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { /// ASN.1 DER-encoded signature data bytes: SignatureBytes<C>, @@ -60,45 +62,45 @@ where s_range: Range<usize>, } -impl<C> signature::Signature for Signature<C> -where - C: PrimeCurve, - MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, -{ - /// Parse an ASN.1 DER-encoded ECDSA signature from a byte slice - fn from_bytes(bytes: &[u8]) -> Result<Self> { - bytes.try_into() - } -} - #[allow(clippy::len_without_is_empty)] impl<C> Signature<C> where C: PrimeCurve, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { - /// 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<Self> { + 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::FieldBytesSize::USIZE + || s.as_bytes().len() > C::FieldBytesSize::USIZE + { + 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::<C>::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<Self> { - let r = UIntRef::new(r)?; - let s = UIntRef::new(s)?; + /// 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<Self> { + let r = UintRef::new(r)?; + let s = UintRef::new(s)?; let mut bytes = SignatureBytes::<C>::default(); let mut writer = der::SliceWriter::new(&mut bytes); @@ -114,6 +116,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()] @@ -129,18 +147,33 @@ impl<C> AsRef<[u8]> for Signature<C> where C: PrimeCurve, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { fn as_ref(&self) -> &[u8] { self.as_bytes() } } -impl<C> fmt::Debug for Signature<C> +impl<C> Clone for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + fn clone(&self) -> Self { + Self { + bytes: self.bytes.clone(), + r_range: self.r_range.clone(), + s_range: self.s_range.clone(), + } + } +} + +impl<C> Debug for Signature<C> where C: PrimeCurve, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ecdsa::der::Signature<{:?}>(", C::default())?; @@ -153,64 +186,125 @@ where } } -impl<C> TryFrom<&[u8]> for Signature<C> +impl<'a, C> Decode<'a> for Signature<C> where C: PrimeCurve, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { - type Error = Error; + fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> { + let header = reader.peek_header()?; + header.tag.assert_eq(Tag::Sequence)?; - fn try_from(input: &[u8]) -> Result<Self> { - let (r, s) = decode_der(input).map_err(|_| Error::new())?; + let mut buf = SignatureBytes::<C>::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()))?; - if r.as_bytes().len() > C::UInt::BYTE_SIZE || s.as_bytes().len() > C::UInt::BYTE_SIZE { - return Err(Error::new()); - } + reader.read_into(slice)?; + Self::from_bytes(slice).map_err(|_| Tag::Integer.value_error()) + } +} - let r_range = find_scalar_range(input, r.as_bytes())?; - let s_range = find_scalar_range(input, s.as_bytes())?; +impl<C> Encode for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + fn encoded_len(&self) -> der::Result<Length> { + Length::try_from(self.len()) + } - if s_range.end != input.len() { - return Err(Error::new()); - } + fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { + writer.write(self.as_bytes()) + } +} - let mut bytes = SignatureBytes::<C>::default(); - bytes[..s_range.end].copy_from_slice(input); +impl<C> FixedTag for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + const TAG: Tag = Tag::Sequence; +} - Ok(Signature { - bytes, - r_range, - s_range, - }) +impl<C> From<crate::Signature<C>> for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + fn from(sig: crate::Signature<C>) -> Signature<C> { + sig.to_der() + } +} + +impl<C> TryFrom<&[u8]> for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + type Error = Error; + + fn try_from(input: &[u8]) -> Result<Self> { + Self::from_bytes(input) } } -impl<C> TryFrom<Signature<C>> for super::Signature<C> +impl<C> TryFrom<Signature<C>> for crate::Signature<C> where C: PrimeCurve, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { type Error = Error; fn try_from(sig: Signature<C>) -> Result<super::Signature<C>> { let mut bytes = super::SignatureBytes::<C>::default(); - let r_begin = C::UInt::BYTE_SIZE.saturating_sub(sig.r().len()); + let r_begin = C::FieldBytesSize::USIZE.saturating_sub(sig.r().len()); let s_begin = bytes.len().saturating_sub(sig.s().len()); - bytes[r_begin..C::UInt::BYTE_SIZE].copy_from_slice(sig.r()); + bytes[r_begin..C::FieldBytesSize::USIZE].copy_from_slice(sig.r()); bytes[s_begin..].copy_from_slice(sig.s()); Self::try_from(bytes.as_slice()) } } +#[cfg(feature = "alloc")] +impl<C> From<Signature<C>> for Box<[u8]> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + fn from(signature: Signature<C>) -> Box<[u8]> { + signature.to_vec().into_boxed_slice() + } +} + +#[cfg(feature = "alloc")] +impl<C> SignatureEncoding for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + type Repr = Box<[u8]>; + + fn to_vec(&self) -> Vec<u8> { + self.as_bytes().into() + } +} + #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<C> Serialize for Signature<C> where C: PrimeCurve, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> where @@ -221,12 +315,11 @@ where } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de, C> Deserialize<'de> for Signature<C> where C: PrimeCurve, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> where @@ -239,14 +332,14 @@ where } /// Decode the `r` and `s` components of a DER-encoded ECDSA signature. -fn decode_der(der_bytes: &[u8]) -> der::Result<(UIntRef<'_>, UIntRef<'_>)> { +fn decode_der(der_bytes: &[u8]) -> der::Result<(UintRef<'_>, UintRef<'_>)> { let mut reader = der::SliceReader::new(der_bytes)?; let header = der::Header::decode(&mut reader)?; header.tag.assert_eq(der::Tag::Sequence)?; let ret = reader.read_nested(header.length, |reader| { - let r = UIntRef::decode(reader)?; - let s = UIntRef::decode(reader)?; + let r = UintRef::decode(reader)?; + let s = UintRef::decode(reader)?; Ok((r, s)) })?; @@ -269,7 +362,7 @@ impl<C> signature::PrehashSignature for Signature<C> where C: PrimeCurve + crate::hazmat::DigestPrimitive, MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { type Digest = C::Digest; } @@ -277,7 +370,6 @@ where #[cfg(all(test, feature = "arithmetic"))] mod tests { use elliptic_curve::dev::MockCurve; - use signature::Signature as _; type Signature = crate::Signature<MockCurve>; @@ -291,7 +383,7 @@ mod tests { #[test] fn test_fixed_to_asn1_signature_roundtrip() { - let signature1 = Signature::from_bytes(&EXAMPLE_SIGNATURE).unwrap(); + let signature1 = Signature::try_from(EXAMPLE_SIGNATURE.as_ref()).unwrap(); // Convert to ASN.1 DER and back let asn1_signature = signature1.to_der(); diff --git a/vendor/ecdsa/src/dev.rs b/vendor/ecdsa/src/dev.rs index ce00c7fbf..8c1b7c876 100644 --- a/vendor/ecdsa/src/dev.rs +++ b/vendor/ecdsa/src/dev.rs @@ -29,19 +29,20 @@ pub struct TestVector { /// Define ECDSA signing test. #[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! new_signing_test { ($curve:path, $vectors:expr) => { use $crate::{ elliptic_curve::{ - bigint::Encoding, generic_array::GenericArray, group::ff::PrimeField, Curve, - ProjectiveArithmetic, Scalar, + bigint::Encoding, + generic_array::{typenum::Unsigned, GenericArray}, + group::ff::PrimeField, + Curve, CurveArithmetic, Scalar, }, hazmat::SignPrimitive, }; fn decode_scalar(bytes: &[u8]) -> Option<Scalar<$curve>> { - if bytes.len() == <$curve as Curve>::UInt::BYTE_SIZE { + if bytes.len() == <$curve as Curve>::FieldBytesSize::USIZE { Scalar::<$curve>::from_repr(GenericArray::clone_from_slice(bytes)).into() } else { None @@ -53,8 +54,14 @@ macro_rules! new_signing_test { for vector in $vectors { let d = decode_scalar(vector.d).expect("invalid vector.d"); let k = decode_scalar(vector.k).expect("invalid vector.m"); + + assert_eq!( + <$curve as Curve>::FieldBytesSize::USIZE, + vector.m.len(), + "invalid vector.m (must be field-sized digest)" + ); let z = GenericArray::clone_from_slice(vector.m); - let sig = d.try_sign_prehashed(k, z).expect("ECDSA sign failed").0; + let sig = d.try_sign_prehashed(k, &z).expect("ECDSA sign failed").0; assert_eq!(vector.r, sig.r().to_bytes().as_slice()); assert_eq!(vector.s, sig.s().to_bytes().as_slice()); @@ -65,7 +72,6 @@ macro_rules! new_signing_test { /// Define ECDSA verification test. #[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! new_verification_test { ($curve:path, $vectors:expr) => { use $crate::{ @@ -73,7 +79,7 @@ macro_rules! new_verification_test { generic_array::GenericArray, group::ff::PrimeField, sec1::{EncodedPoint, FromEncodedPoint}, - AffinePoint, ProjectiveArithmetic, Scalar, + AffinePoint, CurveArithmetic, Scalar, }, hazmat::VerifyPrimitive, Signature, @@ -97,7 +103,7 @@ macro_rules! new_verification_test { ) .unwrap(); - let result = q.verify_prehashed(z, &sig); + let result = q.verify_prehashed(&z, &sig); assert!(result.is_ok()); } } @@ -122,7 +128,7 @@ macro_rules! new_verification_test { Signature::from_scalars(GenericArray::clone_from_slice(vector.r), s_tweaked) .unwrap(); - let result = q.verify_prehashed(z, &sig); + let result = q.verify_prehashed(&z, &sig); assert!(result.is_err()); } } @@ -133,10 +139,13 @@ macro_rules! new_verification_test { /// Define a Wycheproof verification test. #[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! new_wycheproof_test { ($name:ident, $test_name: expr, $curve:path) => { - use $crate::{elliptic_curve::sec1::EncodedPoint, signature::Verifier, Signature}; + use $crate::{ + elliptic_curve::{bigint::Integer, sec1::EncodedPoint}, + signature::Verifier, + Signature, + }; #[test] fn $name() { @@ -148,7 +157,7 @@ macro_rules! new_wycheproof_test { fn element_from_padded_slice<C: elliptic_curve::Curve>( data: &[u8], ) -> elliptic_curve::FieldBytes<C> { - let point_len = C::UInt::BYTE_SIZE; + let point_len = C::FieldBytesSize::USIZE; if data.len() >= point_len { let offset = data.len() - point_len; for v in data.iter().take(offset) { diff --git a/vendor/ecdsa/src/hazmat.rs b/vendor/ecdsa/src/hazmat.rs index 3ca3fc4ce..6e59f2e2e 100644 --- a/vendor/ecdsa/src/hazmat.rs +++ b/vendor/ecdsa/src/hazmat.rs @@ -10,50 +10,53 @@ //! Failure to use them correctly can lead to catastrophic failures including //! FULL PRIVATE KEY RECOVERY! +use crate::{Error, Result}; +use core::cmp; +use elliptic_curve::{generic_array::typenum::Unsigned, FieldBytes, PrimeCurve}; + #[cfg(feature = "arithmetic")] use { crate::{RecoveryId, SignatureSize}, - core::borrow::Borrow, elliptic_curve::{ - group::Curve as _, - ops::{Invert, LinearCombination, Reduce}, + ff::PrimeField, + group::{Curve as _, Group}, + ops::{Invert, LinearCombination, MulByGenerator, Reduce}, + point::AffineCoordinates, + scalar::IsHigh, subtle::CtOption, - AffineArithmetic, AffineXCoordinate, Field, Group, ProjectiveArithmetic, ProjectivePoint, - Scalar, ScalarArithmetic, + CurveArithmetic, ProjectivePoint, Scalar, }, }; #[cfg(feature = "digest")] use { - core::cmp, - elliptic_curve::{bigint::Encoding, FieldSize}, - signature::{digest::Digest, PrehashSignature}, -}; - -#[cfg(any(feature = "arithmetic", feature = "digest"))] -use crate::{ - elliptic_curve::{generic_array::ArrayLength, FieldBytes, PrimeCurve}, - Error, Result, Signature, + elliptic_curve::FieldBytesSize, + signature::{ + digest::{core_api::BlockSizeUser, Digest, FixedOutput, FixedOutputReset}, + PrehashSignature, + }, }; -#[cfg(all(feature = "arithmetic", feature = "digest"))] -use signature::digest::FixedOutput; +#[cfg(feature = "rfc6979")] +use elliptic_curve::{FieldBytesEncoding, ScalarPrimitive}; -#[cfg(all(feature = "rfc6979"))] -use { - elliptic_curve::ScalarCore, - signature::digest::{core_api::BlockSizeUser, FixedOutputReset}, -}; +#[cfg(any(feature = "arithmetic", feature = "digest"))] +use crate::{elliptic_curve::generic_array::ArrayLength, Signature}; /// Try to sign the given prehashed message using ECDSA. /// /// This trait is intended to be implemented on a type with access to the /// secret scalar via `&self`, such as particular curve's `Scalar` type. #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub trait SignPrimitive<C>: Field + Into<FieldBytes<C>> + Reduce<C::UInt> + Sized +pub trait SignPrimitive<C>: + AsRef<Self> + + Into<FieldBytes<C>> + + IsHigh + + PrimeField<Repr = FieldBytes<C>> + + Reduce<C::Uint, Bytes = FieldBytes<C>> + + Sized where - C: PrimeCurve + ProjectiveArithmetic + ScalarArithmetic<Scalar = Self>, + C: PrimeCurve + CurveArithmetic + CurveArithmetic<Scalar = Self>, SignatureSize<C>: ArrayLength<u8>, { /// Try to sign the prehashed message. @@ -72,26 +75,27 @@ where fn try_sign_prehashed<K>( &self, k: K, - z: FieldBytes<C>, + z: &FieldBytes<C>, ) -> Result<(Signature<C>, Option<RecoveryId>)> where - K: Borrow<Self> + Invert<Output = CtOption<Self>>, + K: AsRef<Self> + Invert<Output = CtOption<Self>>, { - if k.borrow().is_zero().into() { + if k.as_ref().is_zero().into() { return Err(Error::new()); } - let z = Self::from_be_bytes_reduced(z); + let z = <Self as Reduce<C::Uint>>::reduce_bytes(z); // Compute scalar inversion of 𝑘 let k_inv = Option::<Scalar<C>>::from(k.invert()).ok_or_else(Error::new)?; // Compute 𝑹 = 𝑘×𝑮 - let R = (C::ProjectivePoint::generator() * k.borrow()).to_affine(); + let R = ProjectivePoint::<C>::mul_by_generator(k.as_ref()).to_affine(); // Lift x-coordinate of 𝑹 (element of base field) into a serialized big // integer, then reduce it into an element of the scalar field - let r = Self::from_be_bytes_reduced(R.x()); + let r = Self::reduce_bytes(&R.x()); + let x_is_reduced = r.to_repr() != R.x(); // Compute 𝒔 as a signature over 𝒓 and 𝒛. let s = k_inv * (z + (r * self)); @@ -100,8 +104,9 @@ where return Err(Error::new()); } - // TODO(tarcieri): support for computing recovery ID - Ok((Signature::from_scalars(r, s)?, None)) + let signature = Signature::from_scalars(r, s)?; + let recovery_id = RecoveryId::new(R.y_is_odd().into(), x_is_reduced); + Ok((signature, Some(recovery_id))) } /// Try to sign the given message digest deterministically using the method @@ -113,40 +118,24 @@ where /// /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979 #[cfg(all(feature = "rfc6979"))] - #[cfg_attr(docsrs, doc(cfg(feature = "rfc6979")))] fn try_sign_prehashed_rfc6979<D>( &self, - z: FieldBytes<C>, + z: &FieldBytes<C>, ad: &[u8], ) -> Result<(Signature<C>, Option<RecoveryId>)> where - Self: From<ScalarCore<C>>, - C::UInt: for<'a> From<&'a Self>, - D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset, + Self: From<ScalarPrimitive<C>> + Invert<Output = CtOption<Self>>, + D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldBytesSize<C>> + FixedOutputReset, { - let x = C::UInt::from(self); - let k = rfc6979::generate_k::<D, C::UInt>(&x, &C::ORDER, &z, ad); - let k = Self::from(ScalarCore::<C>::new(*k).unwrap()); - self.try_sign_prehashed(k, z) - } + let k = Scalar::<C>::from_repr(rfc6979::generate_k::<D, _>( + &self.to_repr(), + &C::ORDER.encode_field_bytes(), + z, + ad, + )) + .unwrap(); - /// Try to sign the given digest instance using the method described in - /// [RFC6979]. - /// - /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979 - #[cfg(all(feature = "rfc6979"))] - #[cfg_attr(docsrs, doc(cfg(feature = "rfc6979")))] - fn try_sign_digest_rfc6979<D>( - &self, - msg_digest: D, - ad: &[u8], - ) -> Result<(Signature<C>, Option<RecoveryId>)> - where - Self: From<ScalarCore<C>>, - C::UInt: for<'a> From<&'a Self>, - D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset, - { - self.try_sign_prehashed_rfc6979::<D>(msg_digest.finalize_fixed(), ad) + self.try_sign_prehashed::<Self>(k, z) } } @@ -156,11 +145,9 @@ where /// the affine point represeting the public key via `&self`, such as a /// particular curve's `AffinePoint` type. #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub trait VerifyPrimitive<C>: AffineXCoordinate<C> + Copy + Sized +pub trait VerifyPrimitive<C>: AffineCoordinates<FieldRepr = FieldBytes<C>> + Copy + Sized where - C: PrimeCurve + AffineArithmetic<AffinePoint = Self> + ProjectiveArithmetic, - Scalar<C>: Reduce<C::UInt>, + C: PrimeCurve + CurveArithmetic<AffinePoint = Self> + CurveArithmetic, SignatureSize<C>: ArrayLength<u8>, { /// Verify the prehashed message against the provided signature @@ -170,10 +157,10 @@ where /// - `z`: message digest to be verified. MUST BE OUTPUT OF A /// CRYPTOGRAPHICALLY SECURE DIGEST ALGORITHM!!! /// - `sig`: signature to be verified against the key and message - fn verify_prehashed(&self, z: FieldBytes<C>, sig: &Signature<C>) -> Result<()> { - let z = Scalar::<C>::from_be_bytes_reduced(z); + fn verify_prehashed(&self, z: &FieldBytes<C>, sig: &Signature<C>) -> Result<()> { + let z = Scalar::<C>::reduce_bytes(z); let (r, s) = sig.split_scalars(); - let s_inv = *s.invert(); + let s_inv = *s.invert_vartime(); let u1 = z * s_inv; let u2 = *r * s_inv; let x = ProjectivePoint::<C>::lincomb( @@ -185,7 +172,7 @@ where .to_affine() .x(); - if Scalar::<C>::from_be_bytes_reduced(x) == *r { + if *r == Scalar::<C>::reduce_bytes(&x) { Ok(()) } else { Err(Error::new()) @@ -194,12 +181,11 @@ where /// Verify message digest against the provided signature. #[cfg(feature = "digest")] - #[cfg_attr(docsrs, doc(cfg(feature = "digest")))] fn verify_digest<D>(&self, msg_digest: D, sig: &Signature<C>) -> Result<()> where - D: FixedOutput<OutputSize = FieldSize<C>>, + D: FixedOutput<OutputSize = FieldBytesSize<C>>, { - self.verify_prehashed(msg_digest.finalize_fixed(), sig) + self.verify_prehashed(&msg_digest.finalize_fixed(), sig) } } @@ -214,48 +200,91 @@ where /// /// [1]: https://github.com/RustCrypto/traits/tree/master/signature/derive #[cfg(feature = "digest")] -#[cfg_attr(docsrs, doc(cfg(feature = "digest")))] pub trait DigestPrimitive: PrimeCurve { /// Preferred digest to use when computing ECDSA signatures for this /// elliptic curve. This is typically a member of the SHA-2 family. - // TODO(tarcieri): add BlockSizeUser + FixedOutput(Reset) bounds in next breaking release - // These bounds ensure the digest algorithm can be used for HMAC-DRBG for RFC6979 - type Digest: Digest; - - /// Compute field bytes for a prehash (message digest), either zero-padding - /// or truncating if the prehash size does not match the field size. - fn prehash_to_field_bytes(prehash: &[u8]) -> Result<FieldBytes<Self>> { - // Minimum allowed prehash size is half the field size - if prehash.len() < Self::UInt::BYTE_SIZE / 2 { - return Err(Error::new()); - } - - let mut field_bytes = FieldBytes::<Self>::default(); - - // This is a operation according to RFC6979 Section 2.3.2. and SEC1 Section 2.3.8. - // https://datatracker.ietf.org/doc/html/rfc6979#section-2.3.2 - // https://www.secg.org/sec1-v2.pdf - match prehash.len().cmp(&Self::UInt::BYTE_SIZE) { - cmp::Ordering::Equal => field_bytes.copy_from_slice(prehash), - cmp::Ordering::Less => { - // If prehash is smaller than the field size, pad with zeroes on the left - field_bytes[(Self::UInt::BYTE_SIZE - prehash.len())..].copy_from_slice(prehash); - } - cmp::Ordering::Greater => { - // If prehash is larger than the field size, truncate - field_bytes.copy_from_slice(&prehash[..Self::UInt::BYTE_SIZE]); - } - } - - Ok(field_bytes) - } + type Digest: BlockSizeUser + + Digest + + FixedOutput<OutputSize = FieldBytesSize<Self>> + + FixedOutputReset; } #[cfg(feature = "digest")] impl<C> PrehashSignature for Signature<C> where C: DigestPrimitive, - <FieldSize<C> as core::ops::Add>::Output: ArrayLength<u8>, + <FieldBytesSize<C> as core::ops::Add>::Output: ArrayLength<u8>, { type Digest = C::Digest; } + +/// Partial implementation of the `bits2int` function as defined in +/// [RFC6979 § 2.3.2] as well as [SEC1] § 2.3.8. +/// +/// This is used to convert a message digest whose size may be smaller or +/// larger than the size of the curve's scalar field into a serialized +/// (unreduced) field element. +/// +/// [RFC6979 § 2.3.2]: https://datatracker.ietf.org/doc/html/rfc6979#section-2.3.2 +/// [SEC1]: https://www.secg.org/sec1-v2.pdf +pub fn bits2field<C: PrimeCurve>(bits: &[u8]) -> Result<FieldBytes<C>> { + // Minimum allowed bits size is half the field size + if bits.len() < C::FieldBytesSize::USIZE / 2 { + return Err(Error::new()); + } + + let mut field_bytes = FieldBytes::<C>::default(); + + match bits.len().cmp(&C::FieldBytesSize::USIZE) { + cmp::Ordering::Equal => field_bytes.copy_from_slice(bits), + cmp::Ordering::Less => { + // If bits is smaller than the field size, pad with zeroes on the left + field_bytes[(C::FieldBytesSize::USIZE - bits.len())..].copy_from_slice(bits); + } + cmp::Ordering::Greater => { + // If bits is larger than the field size, truncate + field_bytes.copy_from_slice(&bits[..C::FieldBytesSize::USIZE]); + } + } + + Ok(field_bytes) +} + +#[cfg(test)] +mod tests { + use super::bits2field; + use elliptic_curve::dev::MockCurve; + use hex_literal::hex; + + #[test] + fn bits2field_too_small() { + assert!(bits2field::<MockCurve>(b"").is_err()); + } + + #[test] + fn bits2field_size_less() { + let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + let field_bytes = bits2field::<MockCurve>(&prehash).unwrap(); + assert_eq!( + field_bytes.as_slice(), + &hex!("00000000000000000000000000000000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") + ); + } + + #[test] + fn bits2field_size_eq() { + let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + let field_bytes = bits2field::<MockCurve>(&prehash).unwrap(); + assert_eq!(field_bytes.as_slice(), &prehash); + } + + #[test] + fn bits2field_size_greater() { + let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + let field_bytes = bits2field::<MockCurve>(&prehash).unwrap(); + assert_eq!( + field_bytes.as_slice(), + &hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") + ); + } +} diff --git a/vendor/ecdsa/src/lib.rs b/vendor/ecdsa/src/lib.rs index 9e339ba8f..4842d507f 100644 --- a/vendor/ecdsa/src/lib.rs +++ b/vendor/ecdsa/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", @@ -60,22 +60,15 @@ extern crate alloc; mod recovery; #[cfg(feature = "der")] -#[cfg_attr(docsrs, doc(cfg(feature = "der")))] pub mod der; - #[cfg(feature = "dev")] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] pub mod dev; - #[cfg(feature = "hazmat")] -#[cfg_attr(docsrs, doc(cfg(feature = "hazmat")))] pub mod hazmat; - -#[cfg(feature = "sign")] -mod sign; - -#[cfg(feature = "verify")] -mod verify; +#[cfg(feature = "signing")] +mod signing; +#[cfg(feature = "verifying")] +mod verifying; pub use crate::recovery::RecoveryId; @@ -83,24 +76,20 @@ pub use crate::recovery::RecoveryId; pub use elliptic_curve::{self, sec1::EncodedPoint, PrimeCurve}; // Re-export the `signature` crate (and select types) -pub use signature::{self, Error, Result}; - -#[cfg(feature = "sign")] -#[cfg_attr(docsrs, doc(cfg(feature = "sign")))] -pub use crate::sign::SigningKey; +pub use signature::{self, Error, Result, SignatureEncoding}; -#[cfg(feature = "verify")] -#[cfg_attr(docsrs, doc(cfg(feature = "verify")))] -pub use crate::verify::VerifyingKey; +#[cfg(feature = "signing")] +pub use crate::signing::SigningKey; +#[cfg(feature = "verifying")] +pub use crate::verifying::VerifyingKey; use core::{ fmt::{self, Debug}, ops::Add, }; use elliptic_curve::{ - bigint::Encoding as _, - generic_array::{sequence::Concat, ArrayLength, GenericArray}, - FieldBytes, FieldSize, ScalarCore, + generic_array::{sequence::Concat, typenum::Unsigned, ArrayLength, GenericArray}, + FieldBytes, FieldBytesSize, ScalarPrimitive, }; #[cfg(feature = "alloc")] @@ -109,14 +98,76 @@ use alloc::vec::Vec; #[cfg(feature = "arithmetic")] use { core::str, - elliptic_curve::{ff::PrimeField, IsHigh, NonZeroScalar, ScalarArithmetic}, + elliptic_curve::{scalar::IsHigh, CurveArithmetic, NonZeroScalar}, +}; + +#[cfg(feature = "digest")] +use digest::{ + const_oid::{AssociatedOid, ObjectIdentifier}, + Digest, +}; + +#[cfg(feature = "pkcs8")] +use elliptic_curve::pkcs8::spki::{ + der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, }; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +use elliptic_curve::pkcs8::spki::{ + self, AlgorithmIdentifierOwned, DynAssociatedAlgorithmIdentifier, +}; + +/// OID for ECDSA with SHA-224 digests. +/// +/// ```text +/// ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 1 } +/// ``` +// TODO(tarcieri): use `ObjectIdentifier::push_arc` when const unwrap is stable +#[cfg(feature = "digest")] +pub const ECDSA_SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.1"); + +/// OID for ECDSA with SHA-256 digests. +/// +/// ```text +/// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } +/// ``` +#[cfg(feature = "digest")] +pub const ECDSA_SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2"); + +/// OID for ECDSA with SHA-384 digests. +/// +/// ```text +/// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } +/// ``` +#[cfg(feature = "digest")] +pub const ECDSA_SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.3"); + +/// OID for ECDSA with SHA-512 digests. +/// +/// ```text +/// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } +/// ``` +#[cfg(feature = "digest")] +pub const ECDSA_SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.4"); + +#[cfg(feature = "digest")] +const SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.4"); +#[cfg(feature = "digest")] +const SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1"); +#[cfg(feature = "digest")] +const SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.2"); +#[cfg(feature = "digest")] +const SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.3"); + /// Size of a fixed sized signature for the given elliptic curve. -pub type SignatureSize<C> = <FieldSize<C> as Add>::Output; +pub type SignatureSize<C> = <FieldBytesSize<C> as Add>::Output; /// Fixed-size byte array containing an ECDSA signature pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>; @@ -144,11 +195,9 @@ pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>; /// The serialization uses a 64-byte fixed encoding when used with binary /// formats, and a hexadecimal encoding when used with text formats. #[derive(Clone, Eq, PartialEq)] -pub struct Signature<C: PrimeCurve> -where - SignatureSize<C>: ArrayLength<u8>, -{ - bytes: SignatureBytes<C>, +pub struct Signature<C: PrimeCurve> { + r: ScalarPrimitive<C>, + s: ScalarPrimitive<C>, } impl<C> Signature<C> @@ -156,13 +205,34 @@ where C: PrimeCurve, SignatureSize<C>: ArrayLength<u8>, { - /// Parse a signature from ASN.1 DER + /// Parse a signature from fixed-with bytes. + pub fn from_bytes(bytes: &SignatureBytes<C>) -> Result<Self> { + let (r_bytes, s_bytes) = bytes.split_at(C::FieldBytesSize::USIZE); + let r = ScalarPrimitive::from_slice(r_bytes).map_err(|_| Error::new())?; + let s = ScalarPrimitive::from_slice(s_bytes).map_err(|_| Error::new())?; + + if r.is_zero().into() || s.is_zero().into() { + return Err(Error::new()); + } + + Ok(Self { r, s }) + } + + /// Parse a signature from a byte slice. + pub fn from_slice(slice: &[u8]) -> Result<Self> { + if slice.len() == SignatureSize::<C>::USIZE { + Self::from_bytes(SignatureBytes::<C>::from_slice(slice)) + } else { + Err(Error::new()) + } + } + + /// Parse a signature from ASN.1 DER. #[cfg(feature = "der")] - #[cfg_attr(docsrs, doc(cfg(feature = "der")))] pub fn from_der(bytes: &[u8]) -> Result<Self> where der::MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, { der::Signature::<C>::try_from(bytes).and_then(Self::try_from) } @@ -175,51 +245,50 @@ where /// Split the signature into its `r` and `s` components, represented as bytes. pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) { - let (r_bytes, s_bytes) = self.bytes.split_at(C::UInt::BYTE_SIZE); + (self.r.to_bytes(), self.s.to_bytes()) + } - ( - GenericArray::clone_from_slice(r_bytes), - GenericArray::clone_from_slice(s_bytes), - ) + /// Serialize this signature as bytes. + pub fn to_bytes(&self) -> SignatureBytes<C> { + let mut bytes = SignatureBytes::<C>::default(); + let (r_bytes, s_bytes) = bytes.split_at_mut(C::FieldBytesSize::USIZE); + r_bytes.copy_from_slice(&self.r.to_bytes()); + s_bytes.copy_from_slice(&self.s.to_bytes()); + bytes } - /// Serialize this signature as ASN.1 DER + /// Serialize this signature as ASN.1 DER. #[cfg(feature = "der")] - #[cfg_attr(docsrs, doc(cfg(feature = "der")))] pub fn to_der(&self) -> der::Signature<C> where der::MaxSize<C>: ArrayLength<u8>, - <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, { - let (r, s) = self.bytes.split_at(C::UInt::BYTE_SIZE); - der::Signature::from_scalar_bytes(r, s).expect("DER encoding error") + let (r, s) = self.split_bytes(); + der::Signature::from_components(&r, &s).expect("DER encoding error") } /// Convert this signature into a byte vector. #[cfg(feature = "alloc")] - #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub fn to_vec(&self) -> Vec<u8> { - self.bytes.to_vec() + self.to_bytes().to_vec() } } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] impl<C> Signature<C> where - C: PrimeCurve + ScalarArithmetic, + C: PrimeCurve + CurveArithmetic, SignatureSize<C>: ArrayLength<u8>, { /// Get the `r` component of this signature pub fn r(&self) -> NonZeroScalar<C> { - NonZeroScalar::try_from(self.split_bytes().0.as_slice()) - .expect("r-component ensured valid in constructor") + NonZeroScalar::new(self.r.into()).unwrap() } /// Get the `s` component of this signature pub fn s(&self) -> NonZeroScalar<C> { - NonZeroScalar::try_from(self.split_bytes().1.as_slice()) - .expect("s-component ensured valid in constructor") + NonZeroScalar::new(self.s.into()).unwrap() } /// Split the signature into its `r` and `s` scalars. @@ -235,9 +304,8 @@ where let s = self.s(); if s.is_high().into() { - let neg_s = -s; let mut result = self.clone(); - result.bytes[C::UInt::BYTE_SIZE..].copy_from_slice(&neg_s.to_repr()); + result.s = ScalarPrimitive::from(-s); Some(result) } else { None @@ -245,48 +313,46 @@ where } } -impl<C> signature::Signature for Signature<C> +impl<C> Copy for Signature<C> where C: PrimeCurve, SignatureSize<C>: ArrayLength<u8>, + <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy, { - fn from_bytes(bytes: &[u8]) -> Result<Self> { - Self::try_from(bytes) - } } -impl<C> AsRef<[u8]> for Signature<C> +impl<C> Debug for Signature<C> where C: PrimeCurve, SignatureSize<C>: ArrayLength<u8>, { - fn as_ref(&self) -> &[u8] { - self.bytes.as_slice() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ecdsa::Signature<{:?}>(", C::default())?; + + for byte in self.to_bytes() { + write!(f, "{:02X}", byte)?; + } + + write!(f, ")") } } -impl<C> Copy for Signature<C> +impl<C> From<Signature<C>> for SignatureBytes<C> where C: PrimeCurve, SignatureSize<C>: ArrayLength<u8>, - <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy, { + fn from(signature: Signature<C>) -> SignatureBytes<C> { + signature.to_bytes() + } } -impl<C> Debug for Signature<C> +impl<C> SignatureEncoding for Signature<C> where C: PrimeCurve, SignatureSize<C>: ArrayLength<u8>, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ecdsa::Signature<{:?}>(", C::default())?; - - for &byte in self.as_ref() { - write!(f, "{:02X}", byte)?; - } - - write!(f, ")") - } + type Repr = SignatureBytes<C>; } impl<C> TryFrom<&[u8]> for Signature<C> @@ -296,22 +362,8 @@ where { type Error = Error; - fn try_from(bytes: &[u8]) -> Result<Self> { - if bytes.len() != C::UInt::BYTE_SIZE * 2 { - return Err(Error::new()); - } - - for scalar_bytes in bytes.chunks_exact(C::UInt::BYTE_SIZE) { - let scalar = ScalarCore::<C>::from_be_slice(scalar_bytes).map_err(|_| Error::new())?; - - if scalar.is_zero().into() { - return Err(Error::new()); - } - } - - Ok(Self { - bytes: GenericArray::clone_from_slice(bytes), - }) + fn try_from(slice: &[u8]) -> Result<Self> { + Self::from_slice(slice) } } @@ -331,7 +383,7 @@ where SignatureSize<C>: ArrayLength<u8>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for byte in &self.bytes { + for byte in self.to_bytes() { write!(f, "{:02x}", byte)?; } Ok(()) @@ -344,7 +396,7 @@ where SignatureSize<C>: ArrayLength<u8>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for byte in &self.bytes { + for byte in self.to_bytes() { write!(f, "{:02X}", byte)?; } Ok(()) @@ -352,16 +404,15 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] impl<C> str::FromStr for Signature<C> where - C: PrimeCurve + ScalarArithmetic, + C: PrimeCurve + CurveArithmetic, SignatureSize<C>: ArrayLength<u8>, { type Err = Error; fn from_str(hex: &str) -> Result<Self> { - if hex.as_bytes().len() != C::UInt::BYTE_SIZE * 4 { + if hex.as_bytes().len() != C::FieldBytesSize::USIZE * 4 { return Err(Error::new()); } @@ -374,7 +425,7 @@ where return Err(Error::new()); } - let (r_hex, s_hex) = hex.split_at(C::UInt::BYTE_SIZE * 2); + let (r_hex, s_hex) = hex.split_at(C::FieldBytesSize::USIZE * 2); let r = r_hex .parse::<NonZeroScalar<C>>() @@ -388,8 +439,40 @@ where } } +/// ECDSA [`ObjectIdentifier`] which identifies the digest used by default +/// with the `Signer` and `Verifier` traits. +/// +/// To support non-default digest algorithms, use the [`SignatureWithOid`] +/// type instead. +#[cfg(all(feature = "digest", feature = "hazmat"))] +impl<C> AssociatedOid for Signature<C> +where + C: hazmat::DigestPrimitive, + C::Digest: AssociatedOid, +{ + const OID: ObjectIdentifier = match ecdsa_oid_for_digest(C::Digest::OID) { + Some(oid) => oid, + None => panic!("no RFC5758 ECDSA OID defined for DigestPrimitive::Digest"), + }; +} + +/// ECDSA `AlgorithmIdentifier` which identifies the digest used by default +/// with the `Signer` and `Verifier` traits. +#[cfg(feature = "pkcs8")] +impl<C> AssociatedAlgorithmIdentifier for Signature<C> +where + C: PrimeCurve, + Self: AssociatedOid, +{ + type Params = AnyRef<'static>; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef { + oid: Self::OID, + parameters: None, + }; +} + #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<C> Serialize for Signature<C> where C: PrimeCurve, @@ -399,12 +482,11 @@ where where S: ser::Serializer, { - serdect::array::serialize_hex_upper_or_bin(&self.bytes, serializer) + serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) } } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de, C> Deserialize<'de> for Signature<C> where C: PrimeCurve, @@ -419,3 +501,194 @@ where Self::try_from(bytes.as_slice()).map_err(de::Error::custom) } } + +/// An extended [`Signature`] type which is parameterized by an +/// `ObjectIdentifier` which identifies the ECDSA variant used by a +/// particular signature. +/// +/// Valid `ObjectIdentifiers` are defined in [RFC5758 § 3.2]: +/// +/// - SHA-224: [`ECDSA_SHA224_OID`] (1.2.840.10045.4.3.1) +/// - SHA-256: [`ECDSA_SHA256_OID`] (1.2.840.10045.4.3.2) +/// - SHA-384: [`ECDSA_SHA384_OID`] (1.2.840.10045.4.3.3) +/// - SHA-512: [`ECDSA_SHA512_OID`] (1.2.840.10045.4.3.4) +/// +/// [RFC5758 § 3.2]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 +#[cfg(feature = "digest")] +#[derive(Clone, Eq, PartialEq)] +pub struct SignatureWithOid<C: PrimeCurve> { + /// Inner signature type. + signature: Signature<C>, + + /// OID which identifies the ECDSA variant used. + /// + /// MUST be one of the ECDSA algorithm variants as defined in RFC5758. + /// + /// These OIDs begin with `1.2.840.10045.4`. + oid: ObjectIdentifier, +} + +#[cfg(feature = "digest")] +impl<C> SignatureWithOid<C> +where + C: PrimeCurve, +{ + /// Create a new signature with an explicitly provided OID. + /// + /// OID must begin with `1.2.840.10045.4`, the [RFC5758] OID prefix for + /// ECDSA variants. + /// + /// [RFC5758]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 + pub fn new(signature: Signature<C>, oid: ObjectIdentifier) -> Result<Self> { + // TODO(tarcieri): use `ObjectIdentifier::starts_with` + for (arc1, arc2) in ObjectIdentifier::new_unwrap("1.2.840.10045.4.3") + .arcs() + .zip(oid.arcs()) + { + if arc1 != arc2 { + return Err(Error::new()); + } + } + + Ok(Self { signature, oid }) + } + + /// Create a new signature, determining the OID from the given digest. + /// + /// Supports SHA-2 family digests as enumerated in [RFC5758 § 3.2], i.e. + /// SHA-224, SHA-256, SHA-384, or SHA-512. + /// + /// [RFC5758 § 3.2]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 + pub fn new_with_digest<D>(signature: Signature<C>) -> Result<Self> + where + D: AssociatedOid + Digest, + { + let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?; + Ok(Self { signature, oid }) + } + + /// Parse a signature from fixed-with bytes. + pub fn from_bytes_with_digest<D>(bytes: &SignatureBytes<C>) -> Result<Self> + where + D: AssociatedOid + Digest, + SignatureSize<C>: ArrayLength<u8>, + { + Self::new_with_digest::<D>(Signature::<C>::from_bytes(bytes)?) + } + + /// Parse a signature from a byte slice. + pub fn from_slice_with_digest<D>(slice: &[u8]) -> Result<Self> + where + D: AssociatedOid + Digest, + SignatureSize<C>: ArrayLength<u8>, + { + Self::new_with_digest::<D>(Signature::<C>::from_slice(slice)?) + } + + /// Get the fixed-width ECDSA signature. + pub fn signature(&self) -> &Signature<C> { + &self.signature + } + + /// Get the ECDSA OID for this signature. + pub fn oid(&self) -> ObjectIdentifier { + self.oid + } + + /// Serialize this signature as bytes. + pub fn to_bytes(&self) -> SignatureBytes<C> + where + SignatureSize<C>: ArrayLength<u8>, + { + self.signature.to_bytes() + } +} + +#[cfg(feature = "digest")] +impl<C> Copy for SignatureWithOid<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, + <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy, +{ +} + +#[cfg(feature = "digest")] +impl<C> From<SignatureWithOid<C>> for Signature<C> +where + C: PrimeCurve, +{ + fn from(sig: SignatureWithOid<C>) -> Signature<C> { + sig.signature + } +} + +#[cfg(feature = "digest")] +impl<C> From<SignatureWithOid<C>> for SignatureBytes<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(signature: SignatureWithOid<C>) -> SignatureBytes<C> { + signature.to_bytes() + } +} + +/// NOTE: this implementation assumes the default digest for the given elliptic +/// curve as defined by [`hazmat::DigestPrimitive`]. +/// +/// When working with alternative digests, you will need to use e.g. +/// [`SignatureWithOid::new_with_digest`]. +#[cfg(all(feature = "digest", feature = "hazmat"))] +impl<C> SignatureEncoding for SignatureWithOid<C> +where + C: hazmat::DigestPrimitive, + C::Digest: AssociatedOid, + SignatureSize<C>: ArrayLength<u8>, +{ + type Repr = SignatureBytes<C>; +} + +/// NOTE: this implementation assumes the default digest for the given elliptic +/// curve as defined by [`hazmat::DigestPrimitive`]. +/// +/// When working with alternative digests, you will need to use e.g. +/// [`SignatureWithOid::new_with_digest`]. +#[cfg(all(feature = "digest", feature = "hazmat"))] +impl<C> TryFrom<&[u8]> for SignatureWithOid<C> +where + C: hazmat::DigestPrimitive, + C::Digest: AssociatedOid, + SignatureSize<C>: ArrayLength<u8>, +{ + type Error = Error; + + fn try_from(slice: &[u8]) -> Result<Self> { + Self::new(Signature::<C>::from_slice(slice)?, C::Digest::OID) + } +} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl<C> DynAssociatedAlgorithmIdentifier for SignatureWithOid<C> +where + C: PrimeCurve, +{ + fn algorithm_identifier(&self) -> spki::Result<AlgorithmIdentifierOwned> { + Ok(AlgorithmIdentifierOwned { + oid: self.oid, + parameters: None, + }) + } +} + +/// Get the ECDSA OID for a given digest OID. +#[cfg(feature = "digest")] +const fn ecdsa_oid_for_digest(digest_oid: ObjectIdentifier) -> Option<ObjectIdentifier> { + match digest_oid { + SHA224_OID => Some(ECDSA_SHA224_OID), + SHA256_OID => Some(ECDSA_SHA256_OID), + SHA384_OID => Some(ECDSA_SHA384_OID), + SHA512_OID => Some(ECDSA_SHA512_OID), + _ => None, + } +} diff --git a/vendor/ecdsa/src/recovery.rs b/vendor/ecdsa/src/recovery.rs index c923bbad7..dd1b6aed5 100644 --- a/vendor/ecdsa/src/recovery.rs +++ b/vendor/ecdsa/src/recovery.rs @@ -2,6 +2,38 @@ use crate::{Error, Result}; +#[cfg(feature = "signing")] +use { + crate::{hazmat::SignPrimitive, SigningKey}, + elliptic_curve::subtle::CtOption, + signature::{hazmat::PrehashSigner, DigestSigner, Signer}, +}; + +#[cfg(feature = "verifying")] +use { + crate::{hazmat::VerifyPrimitive, VerifyingKey}, + elliptic_curve::{ + bigint::CheckedAdd, + ops::{LinearCombination, Reduce}, + point::DecompressPoint, + sec1::{self, FromEncodedPoint, ToEncodedPoint}, + AffinePoint, FieldBytesEncoding, FieldBytesSize, Group, PrimeField, ProjectivePoint, + }, + signature::hazmat::PrehashVerifier, +}; + +#[cfg(any(feature = "signing", feature = "verifying"))] +use { + crate::{ + hazmat::{bits2field, DigestPrimitive}, + Signature, SignatureSize, + }, + elliptic_curve::{ + generic_array::ArrayLength, ops::Invert, CurveArithmetic, PrimeCurve, Scalar, + }, + signature::digest::Digest, +}; + /// Recovery IDs, a.k.a. "recid". /// /// This is an integer value `0`, `1`, `2`, or `3` included along with a @@ -55,6 +87,74 @@ impl RecoveryId { } } +#[cfg(feature = "verifying")] +impl RecoveryId { + /// Given a public key, message, and signature, use trial recovery + /// to determine if a suitable recovery ID exists, or return an error + /// otherwise. + pub fn trial_recovery_from_msg<C>( + verifying_key: &VerifyingKey<C>, + msg: &[u8], + signature: &Signature<C>, + ) -> Result<Self> + where + C: DigestPrimitive + PrimeCurve + CurveArithmetic, + AffinePoint<C>: + DecompressPoint<C> + FromEncodedPoint<C> + ToEncodedPoint<C> + VerifyPrimitive<C>, + FieldBytesSize<C>: sec1::ModulusSize, + SignatureSize<C>: ArrayLength<u8>, + { + Self::trial_recovery_from_digest(verifying_key, C::Digest::new_with_prefix(msg), signature) + } + + /// Given a public key, message digest, and signature, use trial recovery + /// to determine if a suitable recovery ID exists, or return an error + /// otherwise. + pub fn trial_recovery_from_digest<C, D>( + verifying_key: &VerifyingKey<C>, + digest: D, + signature: &Signature<C>, + ) -> Result<Self> + where + C: PrimeCurve + CurveArithmetic, + D: Digest, + AffinePoint<C>: + DecompressPoint<C> + FromEncodedPoint<C> + ToEncodedPoint<C> + VerifyPrimitive<C>, + FieldBytesSize<C>: sec1::ModulusSize, + SignatureSize<C>: ArrayLength<u8>, + { + Self::trial_recovery_from_prehash(verifying_key, &digest.finalize(), signature) + } + + /// Given a public key, message digest, and signature, use trial recovery + /// to determine if a suitable recovery ID exists, or return an error + /// otherwise. + pub fn trial_recovery_from_prehash<C>( + verifying_key: &VerifyingKey<C>, + prehash: &[u8], + signature: &Signature<C>, + ) -> Result<Self> + where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: + DecompressPoint<C> + FromEncodedPoint<C> + ToEncodedPoint<C> + VerifyPrimitive<C>, + FieldBytesSize<C>: sec1::ModulusSize, + SignatureSize<C>: ArrayLength<u8>, + { + for id in 0..=Self::MAX { + let recovery_id = RecoveryId(id); + + if let Ok(vk) = VerifyingKey::recover_from_prehash(prehash, signature, recovery_id) { + if verifying_key == &vk { + return Ok(recovery_id); + } + } + } + + Err(Error::new()) + } +} + impl TryFrom<u8> for RecoveryId { type Error = Error; @@ -69,6 +169,153 @@ impl From<RecoveryId> for u8 { } } +#[cfg(feature = "signing")] +impl<C> SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + /// Sign the given message prehash, returning a signature and recovery ID. + pub fn sign_prehash_recoverable(&self, prehash: &[u8]) -> Result<(Signature<C>, RecoveryId)> { + let z = bits2field::<C>(prehash)?; + let (sig, recid) = self + .as_nonzero_scalar() + .try_sign_prehashed_rfc6979::<C::Digest>(&z, &[])?; + + Ok((sig, recid.ok_or_else(Error::new)?)) + } + + /// Sign the given message digest, returning a signature and recovery ID. + pub fn sign_digest_recoverable<D>(&self, msg_digest: D) -> Result<(Signature<C>, RecoveryId)> + where + D: Digest, + { + self.sign_prehash_recoverable(&msg_digest.finalize()) + } + + /// Sign the given message, hashing it with the curve's default digest + /// function, and returning a signature and recovery ID. + pub fn sign_recoverable(&self, msg: &[u8]) -> Result<(Signature<C>, RecoveryId)> { + self.sign_digest_recoverable(C::Digest::new_with_prefix(msg)) + } +} + +#[cfg(feature = "signing")] +impl<C, D> DigestSigner<D, (Signature<C>, RecoveryId)> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: Digest, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result<(Signature<C>, RecoveryId)> { + self.sign_digest_recoverable(msg_digest) + } +} + +#[cfg(feature = "signing")] +impl<C> PrehashSigner<(Signature<C>, RecoveryId)> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn sign_prehash(&self, prehash: &[u8]) -> Result<(Signature<C>, RecoveryId)> { + self.sign_prehash_recoverable(prehash) + } +} + +#[cfg(feature = "signing")] +impl<C> Signer<(Signature<C>, RecoveryId)> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn try_sign(&self, msg: &[u8]) -> Result<(Signature<C>, RecoveryId)> { + self.sign_recoverable(msg) + } +} + +#[cfg(feature = "verifying")] +impl<C> VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: + DecompressPoint<C> + FromEncodedPoint<C> + ToEncodedPoint<C> + VerifyPrimitive<C>, + FieldBytesSize<C>: sec1::ModulusSize, + SignatureSize<C>: ArrayLength<u8>, +{ + /// Recover a [`VerifyingKey`] from the given message, signature, and + /// [`RecoveryId`]. + /// + /// The message is first hashed using this curve's [`DigestPrimitive`]. + pub fn recover_from_msg( + msg: &[u8], + signature: &Signature<C>, + recovery_id: RecoveryId, + ) -> Result<Self> + where + C: DigestPrimitive, + { + Self::recover_from_digest(C::Digest::new_with_prefix(msg), signature, recovery_id) + } + + /// Recover a [`VerifyingKey`] from the given message [`Digest`], + /// signature, and [`RecoveryId`]. + pub fn recover_from_digest<D>( + msg_digest: D, + signature: &Signature<C>, + recovery_id: RecoveryId, + ) -> Result<Self> + where + D: Digest, + { + Self::recover_from_prehash(&msg_digest.finalize(), signature, recovery_id) + } + + /// Recover a [`VerifyingKey`] from the given `prehash` of a message, the + /// signature over that prehashed message, and a [`RecoveryId`]. + #[allow(non_snake_case)] + pub fn recover_from_prehash( + prehash: &[u8], + signature: &Signature<C>, + recovery_id: RecoveryId, + ) -> Result<Self> { + let (r, s) = signature.split_scalars(); + let z = <Scalar<C> as Reduce<C::Uint>>::reduce_bytes(&bits2field::<C>(prehash)?); + + let mut r_bytes = r.to_repr(); + if recovery_id.is_x_reduced() { + match Option::<C::Uint>::from( + C::Uint::decode_field_bytes(&r_bytes).checked_add(&C::ORDER), + ) { + Some(restored) => r_bytes = restored.encode_field_bytes(), + // No reduction should happen here if r was reduced + None => return Err(Error::new()), + }; + } + let R = AffinePoint::<C>::decompress(&r_bytes, u8::from(recovery_id.is_y_odd()).into()); + + if R.is_none().into() { + return Err(Error::new()); + } + + let R = ProjectivePoint::<C>::from(R.unwrap()); + let r_inv = *r.invert(); + let u1 = -(r_inv * z); + let u2 = r_inv * *s; + let pk = ProjectivePoint::<C>::lincomb(&ProjectivePoint::<C>::generator(), &u1, &R, &u2); + let vk = Self::from_affine(pk.into())?; + + // Ensure signature verifies with the recovered key + vk.verify_prehash(prehash, signature)?; + + Ok(vk) + } +} + #[cfg(test)] mod tests { use super::RecoveryId; diff --git a/vendor/ecdsa/src/sign.rs b/vendor/ecdsa/src/sign.rs deleted file mode 100644 index 12d00edb2..000000000 --- a/vendor/ecdsa/src/sign.rs +++ /dev/null @@ -1,424 +0,0 @@ -//! ECDSA signing key. - -// TODO(tarcieri): support for hardware crypto accelerators - -use crate::{ - hazmat::{DigestPrimitive, SignPrimitive}, - Error, Result, Signature, SignatureSize, -}; -use core::fmt::{self, Debug}; -use elliptic_curve::{ - generic_array::ArrayLength, - group::ff::PrimeField, - ops::{Invert, Reduce}, - subtle::{Choice, ConstantTimeEq, CtOption}, - zeroize::{Zeroize, ZeroizeOnDrop}, - FieldBytes, FieldSize, NonZeroScalar, PrimeCurve, ProjectiveArithmetic, Scalar, SecretKey, -}; -use signature::{ - digest::{core_api::BlockSizeUser, Digest, FixedOutput, FixedOutputReset}, - hazmat::PrehashSigner, - rand_core::{CryptoRng, RngCore}, - DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer, -}; - -#[cfg(feature = "pem")] -use { - crate::elliptic_curve::pkcs8::{EncodePrivateKey, SecretDocument}, - core::str::FromStr, -}; - -#[cfg(feature = "pkcs8")] -use crate::elliptic_curve::{ - pkcs8::{self, AssociatedOid, DecodePrivateKey}, - sec1::{self, FromEncodedPoint, ToEncodedPoint}, - AffinePoint, -}; - -#[cfg(feature = "verify")] -use {crate::verify::VerifyingKey, elliptic_curve::PublicKey, signature::Keypair}; - -/// ECDSA signing key. Generic over elliptic curves. -/// -/// Requires an [`elliptic_curve::ProjectiveArithmetic`] impl on the curve, and a -/// [`SignPrimitive`] impl on its associated `Scalar` type. -#[derive(Clone)] -#[cfg_attr(docsrs, doc(cfg(feature = "sign")))] -pub struct SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - /// ECDSA signing keys are non-zero elements of a given curve's scalar field. - secret_scalar: NonZeroScalar<C>, - - /// Verifying key which corresponds to this signing key. - #[cfg(feature = "verify")] - verifying_key: VerifyingKey<C>, -} - -impl<C> SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - /// Generate a cryptographically random [`SigningKey`]. - pub fn random(rng: impl CryptoRng + RngCore) -> Self { - NonZeroScalar::<C>::random(rng).into() - } - - /// Initialize signing key from a raw scalar serialized as a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result<Self> { - SecretKey::<C>::from_be_bytes(bytes) - .map(|sk| sk.to_nonzero_scalar().into()) - .map_err(|_| Error::new()) - } - - /// Serialize this [`SigningKey`] as bytes - pub fn to_bytes(&self) -> FieldBytes<C> { - self.secret_scalar.to_repr() - } - - /// Borrow the secret [`NonZeroScalar`] value for this key. - /// - /// # ⚠️ Warning - /// - /// This value is key material. - /// - /// Please treat it with the care it deserves! - pub fn as_nonzero_scalar(&self) -> &NonZeroScalar<C> { - &self.secret_scalar - } - - /// Get the [`VerifyingKey`] which corresponds to this [`SigningKey`] - // TODO(tarcieri): make this return `&VerifyingKey<C>` in the next breaking release - #[cfg(feature = "verify")] - #[cfg_attr(docsrs, doc(cfg(feature = "verify")))] - pub fn verifying_key(&self) -> VerifyingKey<C> { - self.verifying_key - } -} - -#[cfg(feature = "verify")] -#[cfg_attr(docsrs, doc(cfg(feature = "verify")))] -impl<C> AsRef<VerifyingKey<C>> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn as_ref(&self) -> &VerifyingKey<C> { - &self.verifying_key - } -} - -impl<C> ConstantTimeEq for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn ct_eq(&self, other: &Self) -> Choice { - self.secret_scalar.ct_eq(&other.secret_scalar) - } -} - -impl<C> Debug for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SigningKey").finish_non_exhaustive() - } -} - -impl<C> Drop for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn drop(&mut self) { - self.secret_scalar.zeroize(); - } -} - -impl<C> ZeroizeOnDrop for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ -} - -/// Constant-time comparison -impl<C> Eq for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ -} - -/// Constant-time comparison -impl<C> PartialEq for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn eq(&self, other: &SigningKey<C>) -> bool { - self.ct_eq(other).into() - } -} - -impl<C> From<SecretKey<C>> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn from(secret_key: SecretKey<C>) -> Self { - Self::from(&secret_key) - } -} - -impl<C> From<&SecretKey<C>> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn from(secret_key: &SecretKey<C>) -> Self { - secret_key.to_nonzero_scalar().into() - } -} - -impl<C> From<SigningKey<C>> for SecretKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn from(key: SigningKey<C>) -> Self { - key.secret_scalar.into() - } -} - -impl<C> From<&SigningKey<C>> for SecretKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn from(secret_key: &SigningKey<C>) -> Self { - secret_key.secret_scalar.into() - } -} - -impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - C::UInt: for<'a> From<&'a Scalar<C>>, - D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - - SignatureSize<C>: ArrayLength<u8>, -{ - /// Sign message digest using a deterministic ephemeral scalar (`k`) - /// computed using the algorithm described in [RFC6979 § 3.2]. - /// - /// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3 - fn try_sign_digest(&self, msg_digest: D) -> Result<Signature<C>> { - Ok(self - .secret_scalar - .try_sign_digest_rfc6979::<D>(msg_digest, &[])? - .0) - } -} - -#[cfg(feature = "verify")] -#[cfg_attr(docsrs, doc(cfg(feature = "verify")))] -impl<C> Keypair<Signature<C>> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - type VerifyingKey = VerifyingKey<C>; -} - -impl<C> PrehashSigner<Signature<C>> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, - C::Digest: BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset, - C::UInt: for<'a> From<&'a Scalar<C>>, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> { - let prehash = C::prehash_to_field_bytes(prehash)?; - - Ok(self - .secret_scalar - .try_sign_prehashed_rfc6979::<C::Digest>(prehash, &[])? - .0) - } -} - -impl<C> Signer<Signature<C>> for SigningKey<C> -where - Self: DigestSigner<C::Digest, Signature<C>>, - C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>> { - self.try_sign_digest(C::Digest::new_with_prefix(msg)) - } -} - -impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - C::UInt: for<'a> From<&'a Scalar<C>>, - D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - /// Sign message prehash using an ephemeral scalar (`k`) derived according - /// to a variant of RFC 6979 (Section 3.6) which supplies additional - /// entropy from an RNG. - fn try_sign_digest_with_rng( - &self, - mut rng: impl CryptoRng + RngCore, - msg_digest: D, - ) -> Result<Signature<C>> { - let mut ad = FieldBytes::<C>::default(); - rng.fill_bytes(&mut ad); - Ok(self - .secret_scalar - .try_sign_digest_rfc6979::<D>(msg_digest, &ad)? - .0) - } -} - -impl<C> RandomizedSigner<Signature<C>> for SigningKey<C> -where - Self: RandomizedDigestSigner<C::Digest, Signature<C>>, - C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn try_sign_with_rng(&self, rng: impl CryptoRng + RngCore, msg: &[u8]) -> Result<Signature<C>> { - self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg)) - } -} - -impl<C> From<NonZeroScalar<C>> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn from(secret_scalar: NonZeroScalar<C>) -> Self { - #[cfg(feature = "verify")] - let public_key = PublicKey::from_secret_scalar(&secret_scalar); - - Self { - secret_scalar, - #[cfg(feature = "verify")] - verifying_key: public_key.into(), - } - } -} - -impl<C> TryFrom<&[u8]> for SigningKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - type Error = Error; - - fn try_from(bytes: &[u8]) -> Result<Self> { - Self::from_bytes(bytes) - } -} - -#[cfg(feature = "verify")] -impl<C> From<&SigningKey<C>> for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> { - signing_key.verifying_key() - } -} - -#[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - type Error = pkcs8::Error; - - fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> { - SecretKey::try_from(private_key_info).map(Into::into) - } -} - -#[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] -impl<C> EncodePrivateKey for SigningKey<C> -where - C: AssociatedOid + PrimeCurve + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> { - SecretKey::from(self.secret_scalar).to_pkcs8_der() - } -} - -#[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -impl<C> DecodePrivateKey for SigningKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ -} - -#[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] -impl<C> FromStr for SigningKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, - Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>, - SignatureSize<C>: ArrayLength<u8>, -{ - type Err = Error; - - fn from_str(s: &str) -> Result<Self> { - Self::from_pkcs8_pem(s).map_err(|_| Error::new()) - } -} diff --git a/vendor/ecdsa/src/signing.rs b/vendor/ecdsa/src/signing.rs new file mode 100644 index 000000000..3a40c6db3 --- /dev/null +++ b/vendor/ecdsa/src/signing.rs @@ -0,0 +1,598 @@ +//! ECDSA signing: producing signatures using a [`SigningKey`]. + +use crate::{ + ecdsa_oid_for_digest, + hazmat::{bits2field, DigestPrimitive, SignPrimitive}, + Error, Result, Signature, SignatureSize, SignatureWithOid, +}; +use core::fmt::{self, Debug}; +use digest::{const_oid::AssociatedOid, Digest, FixedOutput}; +use elliptic_curve::{ + generic_array::ArrayLength, + group::ff::PrimeField, + ops::Invert, + subtle::{Choice, ConstantTimeEq, CtOption}, + zeroize::{Zeroize, ZeroizeOnDrop}, + CurveArithmetic, FieldBytes, FieldBytesSize, NonZeroScalar, PrimeCurve, Scalar, SecretKey, +}; +use signature::{ + hazmat::{PrehashSigner, RandomizedPrehashSigner}, + rand_core::CryptoRngCore, + DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer, +}; + +#[cfg(feature = "der")] +use {crate::der, core::ops::Add}; + +#[cfg(feature = "pem")] +use { + crate::elliptic_curve::pkcs8::{DecodePrivateKey, EncodePrivateKey, SecretDocument}, + core::str::FromStr, +}; + +#[cfg(feature = "pkcs8")] +use crate::elliptic_curve::{ + pkcs8::{ + self, + der::AnyRef, + spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}, + ObjectIdentifier, + }, + sec1::{self, FromEncodedPoint, ToEncodedPoint}, + AffinePoint, +}; + +#[cfg(feature = "verifying")] +use {crate::VerifyingKey, elliptic_curve::PublicKey, signature::KeypairRef}; + +/// ECDSA secret key used for signing. Generic over prime order elliptic curves +/// (e.g. NIST P-curves) +/// +/// Requires an [`elliptic_curve::CurveArithmetic`] impl on the curve, and a +/// [`SignPrimitive`] impl on its associated `Scalar` type. +/// +/// ## Usage +/// +/// The [`signature`] crate defines the following traits which are the +/// primary API for signing: +/// +/// - [`Signer`]: sign a message using this key +/// - [`DigestSigner`]: sign the output of a [`Digest`] using this key +/// - [`PrehashSigner`]: sign the low-level raw output bytes of a message digest +/// +/// See the [`p256` crate](https://docs.rs/p256/latest/p256/ecdsa/index.html) +/// for examples of using this type with a concrete elliptic curve. +#[derive(Clone)] +pub struct SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + /// ECDSA signing keys are non-zero elements of a given curve's scalar field. + secret_scalar: NonZeroScalar<C>, + + /// Verifying key which corresponds to this signing key. + #[cfg(feature = "verifying")] + verifying_key: VerifyingKey<C>, +} + +impl<C> SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + /// Generate a cryptographically random [`SigningKey`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + NonZeroScalar::<C>::random(rng).into() + } + + /// Initialize signing key from a raw scalar serialized as a byte array. + pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> { + SecretKey::<C>::from_bytes(bytes) + .map(Into::into) + .map_err(|_| Error::new()) + } + + /// Initialize signing key from a raw scalar serialized as a byte slice. + pub fn from_slice(bytes: &[u8]) -> Result<Self> { + SecretKey::<C>::from_slice(bytes) + .map(Into::into) + .map_err(|_| Error::new()) + } + + /// Serialize this [`SigningKey`] as bytes + pub fn to_bytes(&self) -> FieldBytes<C> { + self.secret_scalar.to_repr() + } + + /// Borrow the secret [`NonZeroScalar`] value for this key. + /// + /// # ⚠️ Warning + /// + /// This value is key material. + /// + /// Please treat it with the care it deserves! + pub fn as_nonzero_scalar(&self) -> &NonZeroScalar<C> { + &self.secret_scalar + } + + /// Get the [`VerifyingKey`] which corresponds to this [`SigningKey`]. + #[cfg(feature = "verifying")] + pub fn verifying_key(&self) -> &VerifyingKey<C> { + &self.verifying_key + } +} + +// +// `*Signer` trait impls +// + +/// Sign message digest using a deterministic ephemeral scalar (`k`) +/// computed using the algorithm described in [RFC6979 § 3.2]. +/// +/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3 +impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result<Signature<C>> { + self.sign_prehash(&msg_digest.finalize_fixed()) + } +} + +/// Sign message prehash using a deterministic ephemeral scalar (`k`) +/// computed using the algorithm described in [RFC6979 § 3.2]. +/// +/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3 +impl<C> PrehashSigner<Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> { + let z = bits2field::<C>(prehash)?; + Ok(self + .secret_scalar + .try_sign_prehashed_rfc6979::<C::Digest>(&z, &[])? + .0) + } +} + +/// Sign message using a deterministic ephemeral scalar (`k`) +/// computed using the algorithm described in [RFC6979 § 3.2]. +/// +/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3 +impl<C> Signer<Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>> { + self.try_sign_digest(C::Digest::new_with_prefix(msg)) + } +} + +impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn try_sign_digest_with_rng( + &self, + rng: &mut impl CryptoRngCore, + msg_digest: D, + ) -> Result<Signature<C>> { + self.sign_prehash_with_rng(rng, &msg_digest.finalize_fixed()) + } +} + +impl<C> RandomizedPrehashSigner<Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn sign_prehash_with_rng( + &self, + rng: &mut impl CryptoRngCore, + prehash: &[u8], + ) -> Result<Signature<C>> { + let z = bits2field::<C>(prehash)?; + let mut ad = FieldBytes::<C>::default(); + rng.fill_bytes(&mut ad); + Ok(self + .secret_scalar + .try_sign_prehashed_rfc6979::<C::Digest>(&z, &ad)? + .0) + } +} + +impl<C> RandomizedSigner<Signature<C>> for SigningKey<C> +where + Self: RandomizedDigestSigner<C::Digest, Signature<C>>, + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn try_sign_with_rng(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> Result<Signature<C>> { + self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg)) + } +} + +impl<C, D> DigestSigner<D, SignatureWithOid<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: AssociatedOid + Digest + FixedOutput<OutputSize = FieldBytesSize<C>>, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result<SignatureWithOid<C>> { + let signature: Signature<C> = self.try_sign_digest(msg_digest)?; + let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?; + SignatureWithOid::new(signature, oid) + } +} + +impl<C> Signer<SignatureWithOid<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + C::Digest: AssociatedOid, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn try_sign(&self, msg: &[u8]) -> Result<SignatureWithOid<C>> { + self.try_sign_digest(C::Digest::new_with_prefix(msg)) + } +} + +#[cfg(feature = "der")] +impl<C> PrehashSigner<der::Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, +{ + fn sign_prehash(&self, prehash: &[u8]) -> Result<der::Signature<C>> { + PrehashSigner::<Signature<C>>::sign_prehash(self, prehash).map(Into::into) + } +} + +#[cfg(feature = "der")] +impl<C> Signer<der::Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, +{ + fn try_sign(&self, msg: &[u8]) -> Result<der::Signature<C>> { + Signer::<Signature<C>>::try_sign(self, msg).map(Into::into) + } +} + +#[cfg(feature = "der")] +impl<C, D> RandomizedDigestSigner<D, der::Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, +{ + fn try_sign_digest_with_rng( + &self, + rng: &mut impl CryptoRngCore, + msg_digest: D, + ) -> Result<der::Signature<C>> { + RandomizedDigestSigner::<D, Signature<C>>::try_sign_digest_with_rng(self, rng, msg_digest) + .map(Into::into) + } +} + +#[cfg(feature = "der")] +impl<C> RandomizedPrehashSigner<der::Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, +{ + fn sign_prehash_with_rng( + &self, + rng: &mut impl CryptoRngCore, + prehash: &[u8], + ) -> Result<der::Signature<C>> { + RandomizedPrehashSigner::<Signature<C>>::sign_prehash_with_rng(self, rng, prehash) + .map(Into::into) + } +} + +#[cfg(feature = "der")] +impl<C> RandomizedSigner<der::Signature<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, +{ + fn try_sign_with_rng( + &self, + rng: &mut impl CryptoRngCore, + msg: &[u8], + ) -> Result<der::Signature<C>> { + RandomizedSigner::<Signature<C>>::try_sign_with_rng(self, rng, msg).map(Into::into) + } +} + +// +// Other trait impls +// + +#[cfg(feature = "verifying")] +impl<C> AsRef<VerifyingKey<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn as_ref(&self) -> &VerifyingKey<C> { + &self.verifying_key + } +} + +impl<C> ConstantTimeEq for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.secret_scalar.ct_eq(&other.secret_scalar) + } +} + +impl<C> Debug for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SigningKey").finish_non_exhaustive() + } +} + +impl<C> Drop for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn drop(&mut self) { + self.secret_scalar.zeroize(); + } +} + +/// Constant-time comparison +impl<C> Eq for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ +} +impl<C> PartialEq for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn eq(&self, other: &SigningKey<C>) -> bool { + self.ct_eq(other).into() + } +} + +impl<C> From<NonZeroScalar<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(secret_scalar: NonZeroScalar<C>) -> Self { + #[cfg(feature = "verifying")] + let public_key = PublicKey::from_secret_scalar(&secret_scalar); + + Self { + secret_scalar, + #[cfg(feature = "verifying")] + verifying_key: public_key.into(), + } + } +} + +impl<C> From<SecretKey<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(secret_key: SecretKey<C>) -> Self { + Self::from(&secret_key) + } +} + +impl<C> From<&SecretKey<C>> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(secret_key: &SecretKey<C>) -> Self { + secret_key.to_nonzero_scalar().into() + } +} + +impl<C> From<SigningKey<C>> for SecretKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(key: SigningKey<C>) -> Self { + key.secret_scalar.into() + } +} + +impl<C> From<&SigningKey<C>> for SecretKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(secret_key: &SigningKey<C>) -> Self { + secret_key.secret_scalar.into() + } +} + +impl<C> TryFrom<&[u8]> for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result<Self> { + Self::from_slice(bytes) + } +} + +impl<C> ZeroizeOnDrop for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ +} + +#[cfg(feature = "verifying")] +impl<C> From<SigningKey<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(signing_key: SigningKey<C>) -> VerifyingKey<C> { + signing_key.verifying_key + } +} + +#[cfg(feature = "verifying")] +impl<C> From<&SigningKey<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> { + signing_key.verifying_key + } +} + +#[cfg(feature = "verifying")] +impl<C> KeypairRef for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + type VerifyingKey = VerifyingKey<C>; +} + +#[cfg(feature = "pkcs8")] +impl<C> AssociatedAlgorithmIdentifier for SigningKey<C> +where + C: AssociatedOid + CurveArithmetic + PrimeCurve, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = + SecretKey::<C>::ALGORITHM_IDENTIFIER; +} + +#[cfg(feature = "pkcs8")] +impl<C> SignatureAlgorithmIdentifier for SigningKey<C> +where + C: PrimeCurve + CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>, +{ + type Params = AnyRef<'static>; + + const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> = + Signature::<C>::ALGORITHM_IDENTIFIER; +} + +#[cfg(feature = "pkcs8")] +impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<C> +where + C: PrimeCurve + AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + type Error = pkcs8::Error; + + fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> { + SecretKey::try_from(private_key_info).map(Into::into) + } +} + +#[cfg(feature = "pem")] +impl<C> EncodePrivateKey for SigningKey<C> +where + C: AssociatedOid + PrimeCurve + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> { + SecretKey::from(self.secret_scalar).to_pkcs8_der() + } +} + +#[cfg(feature = "pem")] +impl<C> FromStr for SigningKey<C> +where + C: PrimeCurve + AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + type Err = Error; + + fn from_str(s: &str) -> Result<Self> { + Self::from_pkcs8_pem(s).map_err(|_| Error::new()) + } +} diff --git a/vendor/ecdsa/src/verify.rs b/vendor/ecdsa/src/verify.rs deleted file mode 100644 index 5aa8bcb8d..000000000 --- a/vendor/ecdsa/src/verify.rs +++ /dev/null @@ -1,325 +0,0 @@ -//! ECDSA verification key. - -use crate::{ - hazmat::{DigestPrimitive, VerifyPrimitive}, - Error, Result, Signature, SignatureSize, -}; -use core::{cmp::Ordering, fmt::Debug}; -use elliptic_curve::{ - generic_array::ArrayLength, - ops::Reduce, - sec1::{self, EncodedPoint, FromEncodedPoint, ToEncodedPoint}, - AffinePoint, FieldSize, PointCompression, PrimeCurve, ProjectiveArithmetic, PublicKey, Scalar, -}; -use signature::{ - digest::{Digest, FixedOutput}, - hazmat::PrehashVerifier, - DigestVerifier, Verifier, -}; - -#[cfg(feature = "pkcs8")] -use elliptic_curve::pkcs8::{self, AssociatedOid, DecodePublicKey}; - -#[cfg(feature = "pem")] -use elliptic_curve::pkcs8::EncodePublicKey; - -#[cfg(feature = "pem")] -use core::str::FromStr; - -#[cfg(all(feature = "pem", feature = "serde"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))] -use serdect::serde::{de, ser, Deserialize, Serialize}; - -/// ECDSA verification key (i.e. public key). Generic over elliptic curves. -/// -/// Requires an [`elliptic_curve::ProjectiveArithmetic`] impl on the curve, and a -/// [`VerifyPrimitive`] impl on its associated `AffinePoint` type. -/// -/// # `serde` support -/// -/// When the `serde` feature of this crate is enabled, it provides support for -/// serializing and deserializing ECDSA signatures using the `Serialize` and -/// `Deserialize` traits. -/// -/// The serialization leverages the encoding used by the [`PublicKey`] type, -/// which is a binary-oriented ASN.1 DER encoding. -#[cfg_attr(docsrs, doc(cfg(feature = "verify")))] -#[derive(Clone, Debug)] -pub struct VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, -{ - pub(crate) inner: PublicKey<C>, -} - -impl<C> VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - /// Initialize [`VerifyingKey`] from a SEC1-encoded public key. - pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> { - PublicKey::from_sec1_bytes(bytes) - .map(|pk| Self { inner: pk }) - .map_err(|_| Error::new()) - } - - /// Initialize [`VerifyingKey`] from an affine point. - /// - /// Returns an [`Error`] if the given affine point is the additive identity - /// (a.k.a. point at infinity). - pub fn from_affine(affine: AffinePoint<C>) -> Result<Self> { - Ok(Self { - inner: PublicKey::from_affine(affine).map_err(|_| Error::new())?, - }) - } - - /// Initialize [`VerifyingKey`] from an [`EncodedPoint`]. - pub fn from_encoded_point(public_key: &EncodedPoint<C>) -> Result<Self> { - Option::from(PublicKey::<C>::from_encoded_point(public_key)) - .map(|public_key| Self { inner: public_key }) - .ok_or_else(Error::new) - } - - /// Serialize this [`VerifyingKey`] as a SEC1 [`EncodedPoint`], optionally - /// applying point compression. - pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> { - self.inner.to_encoded_point(compress) - } - - /// Borrow the inner [`AffinePoint`] for this public key. - pub fn as_affine(&self) -> &AffinePoint<C> { - self.inner.as_affine() - } -} - -impl<C> AsRef<AffinePoint<C>> for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - fn as_ref(&self) -> &AffinePoint<C> { - self.as_affine() - } -} - -impl<C> Copy for VerifyingKey<C> where C: PrimeCurve + ProjectiveArithmetic {} - -impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - D: Digest + FixedOutput<OutputSize = FieldSize<C>>, - AffinePoint<C>: VerifyPrimitive<C>, - Scalar<C>: Reduce<C::UInt>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn verify_digest(&self, msg_digest: D, signature: &Signature<C>) -> Result<()> { - self.inner.as_affine().verify_digest(msg_digest, signature) - } -} - -impl<C> PrehashVerifier<Signature<C>> for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, - AffinePoint<C>: VerifyPrimitive<C>, - Scalar<C>: Reduce<C::UInt>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn verify_prehash(&self, prehash: &[u8], signature: &Signature<C>) -> Result<()> { - let prehash = C::prehash_to_field_bytes(prehash)?; - self.inner.as_affine().verify_prehashed(prehash, signature) - } -} - -impl<C> Verifier<Signature<C>> for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, - C::Digest: FixedOutput<OutputSize = FieldSize<C>>, - AffinePoint<C>: VerifyPrimitive<C>, - Scalar<C>: Reduce<C::UInt>, - SignatureSize<C>: ArrayLength<u8>, -{ - fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> { - self.verify_digest(C::Digest::new_with_prefix(msg), signature) - } -} - -impl<C> From<&VerifyingKey<C>> for EncodedPoint<C> -where - C: PrimeCurve + ProjectiveArithmetic + PointCompression, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - fn from(verifying_key: &VerifyingKey<C>) -> EncodedPoint<C> { - verifying_key.to_encoded_point(C::COMPRESS_POINTS) - } -} - -impl<C> From<PublicKey<C>> for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, -{ - fn from(public_key: PublicKey<C>) -> VerifyingKey<C> { - VerifyingKey { inner: public_key } - } -} - -impl<C> From<&PublicKey<C>> for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, -{ - fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> { - (*public_key).into() - } -} - -impl<C> From<VerifyingKey<C>> for PublicKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, -{ - fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> { - verifying_key.inner - } -} - -impl<C> From<&VerifyingKey<C>> for PublicKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, -{ - fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> { - (*verifying_key).into() - } -} - -impl<C> Eq for VerifyingKey<C> where C: PrimeCurve + ProjectiveArithmetic {} - -impl<C> PartialEq for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, -{ - fn eq(&self, other: &Self) -> bool { - self.inner.eq(&other.inner) - } -} - -impl<C> PartialOrd for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - self.inner.partial_cmp(&other.inner) - } -} - -impl<C> Ord for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - fn cmp(&self, other: &Self) -> Ordering { - self.inner.cmp(&other.inner) - } -} - -impl<C> TryFrom<&[u8]> for VerifyingKey<C> -where - C: PrimeCurve + ProjectiveArithmetic, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - type Error = Error; - - fn try_from(bytes: &[u8]) -> Result<Self> { - Self::from_sec1_bytes(bytes) - } -} - -#[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -impl<C> TryFrom<pkcs8::SubjectPublicKeyInfo<'_>> for VerifyingKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - type Error = pkcs8::spki::Error; - - fn try_from(spki: pkcs8::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result<Self> { - PublicKey::try_from(spki).map(|inner| Self { inner }) - } -} - -#[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -impl<C> DecodePublicKey for VerifyingKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ -} - -#[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] -impl<C> EncodePublicKey for VerifyingKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - fn to_public_key_der(&self) -> pkcs8::spki::Result<pkcs8::Document> { - self.inner.to_public_key_der() - } -} - -#[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] -impl<C> FromStr for VerifyingKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - type Err = Error; - - fn from_str(s: &str) -> Result<Self> { - Self::from_public_key_pem(s).map_err(|_| Error::new()) - } -} - -#[cfg(all(feature = "pem", feature = "serde"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))] -impl<C> Serialize for VerifyingKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> - where - S: ser::Serializer, - { - self.inner.serialize(serializer) - } -} - -#[cfg(all(feature = "pem", feature = "serde"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))] -impl<'de, C> Deserialize<'de> for VerifyingKey<C> -where - C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression, - AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: sec1::ModulusSize, -{ - fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> - where - D: de::Deserializer<'de>, - { - PublicKey::<C>::deserialize(deserializer).map(Into::into) - } -} diff --git a/vendor/ecdsa/src/verifying.rs b/vendor/ecdsa/src/verifying.rs new file mode 100644 index 000000000..4ac0570ca --- /dev/null +++ b/vendor/ecdsa/src/verifying.rs @@ -0,0 +1,482 @@ +//! ECDSA verifying: checking signatures are authentic using a [`VerifyingKey`]. + +use crate::{ + hazmat::{bits2field, DigestPrimitive, VerifyPrimitive}, + Error, Result, Signature, SignatureSize, +}; +use core::{cmp::Ordering, fmt::Debug}; +use elliptic_curve::{ + generic_array::ArrayLength, + point::PointCompression, + sec1::{self, CompressedPoint, EncodedPoint, FromEncodedPoint, ToEncodedPoint}, + AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey, +}; +use signature::{ + digest::{Digest, FixedOutput}, + hazmat::PrehashVerifier, + DigestVerifier, Verifier, +}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +#[cfg(feature = "der")] +use {crate::der, core::ops::Add}; + +#[cfg(feature = "pem")] +use { + core::str::FromStr, + elliptic_curve::pkcs8::{DecodePublicKey, EncodePublicKey}, +}; + +#[cfg(feature = "pkcs8")] +use elliptic_curve::pkcs8::{ + self, + der::AnyRef, + spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}, + AssociatedOid, ObjectIdentifier, +}; + +#[cfg(feature = "sha2")] +use { + crate::{ + SignatureWithOid, ECDSA_SHA224_OID, ECDSA_SHA256_OID, ECDSA_SHA384_OID, ECDSA_SHA512_OID, + }, + sha2::{Sha224, Sha256, Sha384, Sha512}, +}; + +#[cfg(all(feature = "pem", feature = "serde"))] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// ECDSA public key used for verifying signatures. Generic over prime order +/// elliptic curves (e.g. NIST P-curves) +/// +/// Requires an [`elliptic_curve::CurveArithmetic`] impl on the curve, and a +/// [`VerifyPrimitive`] impl on its associated `AffinePoint` type. +/// +/// ## Usage +/// +/// The [`signature`] crate defines the following traits which are the +/// primary API for verifying: +/// +/// - [`Verifier`]: verify a message against a provided key and signature +/// - [`DigestVerifier`]: verify a message [`Digest`] against a provided key and signature +/// - [`PrehashVerifier`]: verify the low-level raw output bytes of a message digest +/// +/// See the [`p256` crate](https://docs.rs/p256/latest/p256/ecdsa/index.html) +/// for examples of using this type with a concrete elliptic curve. +/// +/// # `serde` support +/// +/// When the `serde` feature of this crate is enabled, it provides support for +/// serializing and deserializing ECDSA signatures using the `Serialize` and +/// `Deserialize` traits. +/// +/// The serialization leverages the encoding used by the [`PublicKey`] type, +/// which is a binary-oriented ASN.1 DER encoding. +#[derive(Clone, Debug)] +pub struct VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, +{ + pub(crate) inner: PublicKey<C>, +} + +impl<C> VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + /// Initialize [`VerifyingKey`] from a SEC1-encoded public key. + pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> { + PublicKey::from_sec1_bytes(bytes) + .map(|pk| Self { inner: pk }) + .map_err(|_| Error::new()) + } + + /// Initialize [`VerifyingKey`] from an affine point. + /// + /// Returns an [`Error`] if the given affine point is the additive identity + /// (a.k.a. point at infinity). + pub fn from_affine(affine: AffinePoint<C>) -> Result<Self> { + Ok(Self { + inner: PublicKey::from_affine(affine).map_err(|_| Error::new())?, + }) + } + + /// Initialize [`VerifyingKey`] from an [`EncodedPoint`]. + pub fn from_encoded_point(public_key: &EncodedPoint<C>) -> Result<Self> { + Option::from(PublicKey::<C>::from_encoded_point(public_key)) + .map(|public_key| Self { inner: public_key }) + .ok_or_else(Error::new) + } + + /// Serialize this [`VerifyingKey`] as a SEC1 [`EncodedPoint`], optionally + /// applying point compression. + pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> { + self.inner.to_encoded_point(compress) + } + + /// Convert this [`VerifyingKey`] into the + /// `Elliptic-Curve-Point-to-Octet-String` encoding described in + /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3 + /// (page 10). + /// + /// <http://www.secg.org/sec1-v2.pdf> + #[cfg(feature = "alloc")] + pub fn to_sec1_bytes(&self) -> Box<[u8]> + where + C: PointCompression, + { + self.inner.to_sec1_bytes() + } + + /// Borrow the inner [`AffinePoint`] for this public key. + pub fn as_affine(&self) -> &AffinePoint<C> { + self.inner.as_affine() + } +} + +// +// `*Verifier` trait impls +// + +impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>, + AffinePoint<C>: VerifyPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn verify_digest(&self, msg_digest: D, signature: &Signature<C>) -> Result<()> { + self.inner.as_affine().verify_digest(msg_digest, signature) + } +} + +impl<C> PrehashVerifier<Signature<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: VerifyPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn verify_prehash(&self, prehash: &[u8], signature: &Signature<C>) -> Result<()> { + let field = bits2field::<C>(prehash)?; + self.inner.as_affine().verify_prehashed(&field, signature) + } +} + +impl<C> Verifier<Signature<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + AffinePoint<C>: VerifyPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> { + self.verify_digest(C::Digest::new_with_prefix(msg), signature) + } +} + +#[cfg(feature = "sha2")] +impl<C> Verifier<SignatureWithOid<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + AffinePoint<C>: VerifyPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, +{ + fn verify(&self, msg: &[u8], sig: &SignatureWithOid<C>) -> Result<()> { + match sig.oid() { + ECDSA_SHA224_OID => self.verify_prehash(&Sha224::digest(msg), sig.signature()), + ECDSA_SHA256_OID => self.verify_prehash(&Sha256::digest(msg), sig.signature()), + ECDSA_SHA384_OID => self.verify_prehash(&Sha384::digest(msg), sig.signature()), + ECDSA_SHA512_OID => self.verify_prehash(&Sha512::digest(msg), sig.signature()), + _ => Err(Error::new()), + } + } +} + +#[cfg(feature = "der")] +impl<C, D> DigestVerifier<D, der::Signature<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>, + AffinePoint<C>: VerifyPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, +{ + fn verify_digest(&self, msg_digest: D, signature: &der::Signature<C>) -> Result<()> { + let signature = Signature::<C>::try_from(signature.clone())?; + DigestVerifier::<D, Signature<C>>::verify_digest(self, msg_digest, &signature) + } +} + +#[cfg(feature = "der")] +impl<C> PrehashVerifier<der::Signature<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + AffinePoint<C>: VerifyPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, +{ + fn verify_prehash(&self, prehash: &[u8], signature: &der::Signature<C>) -> Result<()> { + let signature = Signature::<C>::try_from(signature.clone())?; + PrehashVerifier::<Signature<C>>::verify_prehash(self, prehash, &signature) + } +} + +#[cfg(feature = "der")] +impl<C> Verifier<der::Signature<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + AffinePoint<C>: VerifyPrimitive<C>, + SignatureSize<C>: ArrayLength<u8>, + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, +{ + fn verify(&self, msg: &[u8], signature: &der::Signature<C>) -> Result<()> { + let signature = Signature::<C>::try_from(signature.clone())?; + Verifier::<Signature<C>>::verify(self, msg, &signature) + } +} + +// +// Other trait impls +// + +impl<C> AsRef<AffinePoint<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn as_ref(&self) -> &AffinePoint<C> { + self.as_affine() + } +} + +impl<C> Copy for VerifyingKey<C> where C: PrimeCurve + CurveArithmetic {} + +impl<C> From<VerifyingKey<C>> for CompressedPoint<C> +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn from(verifying_key: VerifyingKey<C>) -> CompressedPoint<C> { + verifying_key.inner.into() + } +} + +impl<C> From<&VerifyingKey<C>> for CompressedPoint<C> +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn from(verifying_key: &VerifyingKey<C>) -> CompressedPoint<C> { + verifying_key.inner.into() + } +} + +impl<C> From<VerifyingKey<C>> for EncodedPoint<C> +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn from(verifying_key: VerifyingKey<C>) -> EncodedPoint<C> { + verifying_key.inner.into() + } +} + +impl<C> From<&VerifyingKey<C>> for EncodedPoint<C> +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn from(verifying_key: &VerifyingKey<C>) -> EncodedPoint<C> { + verifying_key.inner.into() + } +} + +impl<C> Eq for VerifyingKey<C> where C: PrimeCurve + CurveArithmetic {} + +impl<C> PartialEq for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, +{ + fn eq(&self, other: &Self) -> bool { + self.inner.eq(&other.inner) + } +} + +impl<C> From<PublicKey<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, +{ + fn from(public_key: PublicKey<C>) -> VerifyingKey<C> { + VerifyingKey { inner: public_key } + } +} + +impl<C> From<&PublicKey<C>> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, +{ + fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> { + (*public_key).into() + } +} + +impl<C> From<VerifyingKey<C>> for PublicKey<C> +where + C: PrimeCurve + CurveArithmetic, +{ + fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> { + verifying_key.inner + } +} + +impl<C> From<&VerifyingKey<C>> for PublicKey<C> +where + C: PrimeCurve + CurveArithmetic, +{ + fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> { + (*verifying_key).into() + } +} + +impl<C> PartialOrd for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.inner.partial_cmp(&other.inner) + } +} + +impl<C> Ord for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.inner.cmp(&other.inner) + } +} + +impl<C> TryFrom<&[u8]> for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result<Self> { + Self::from_sec1_bytes(bytes) + } +} + +#[cfg(feature = "pkcs8")] +impl<C> AssociatedAlgorithmIdentifier for VerifyingKey<C> +where + C: AssociatedOid + CurveArithmetic + PrimeCurve, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = + PublicKey::<C>::ALGORITHM_IDENTIFIER; +} + +#[cfg(feature = "pkcs8")] +impl<C> SignatureAlgorithmIdentifier for VerifyingKey<C> +where + C: PrimeCurve + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, + Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>, +{ + type Params = AnyRef<'static>; + + const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> = + Signature::<C>::ALGORITHM_IDENTIFIER; +} + +#[cfg(feature = "pkcs8")] +impl<C> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for VerifyingKey<C> +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + type Error = pkcs8::spki::Error; + + fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> { + PublicKey::try_from(spki).map(|inner| Self { inner }) + } +} + +#[cfg(feature = "pem")] +impl<C> EncodePublicKey for VerifyingKey<C> +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn to_public_key_der(&self) -> pkcs8::spki::Result<pkcs8::Document> { + self.inner.to_public_key_der() + } +} + +#[cfg(feature = "pem")] +impl<C> FromStr for VerifyingKey<C> +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + type Err = Error; + + fn from_str(s: &str) -> Result<Self> { + Self::from_public_key_pem(s).map_err(|_| Error::new()) + } +} + +#[cfg(all(feature = "pem", feature = "serde"))] +impl<C> Serialize for VerifyingKey<C> +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + self.inner.serialize(serializer) + } +} + +#[cfg(all(feature = "pem", feature = "serde"))] +impl<'de, C> Deserialize<'de> for VerifyingKey<C> +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: sec1::ModulusSize, +{ + fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + PublicKey::<C>::deserialize(deserializer).map(Into::into) + } +} |