diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/ecdsa | |
parent | Initial commit. (diff) | |
download | cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.tar.xz cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ecdsa')
-rw-r--r-- | vendor/ecdsa/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/ecdsa/CHANGELOG.md | 582 | ||||
-rw-r--r-- | vendor/ecdsa/Cargo.toml | 148 | ||||
-rw-r--r-- | vendor/ecdsa/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | vendor/ecdsa/LICENSE-MIT | 25 | ||||
-rw-r--r-- | vendor/ecdsa/README.md | 93 | ||||
-rw-r--r-- | vendor/ecdsa/debian/patches/fix-signature-dep.patch | 13 | ||||
-rw-r--r-- | vendor/ecdsa/debian/patches/series | 1 | ||||
-rw-r--r-- | vendor/ecdsa/src/der.rs | 464 | ||||
-rw-r--r-- | vendor/ecdsa/src/dev.rs | 230 | ||||
-rw-r--r-- | vendor/ecdsa/src/hazmat.rs | 332 | ||||
-rw-r--r-- | vendor/ecdsa/src/lib.rs | 708 | ||||
-rw-r--r-- | vendor/ecdsa/src/recovery.rs | 357 | ||||
-rw-r--r-- | vendor/ecdsa/src/signing.rs | 598 | ||||
-rw-r--r-- | vendor/ecdsa/src/verifying.rs | 482 | ||||
-rw-r--r-- | vendor/ecdsa/tests/lib.rs | 14 |
16 files changed, 4249 insertions, 0 deletions
diff --git a/vendor/ecdsa/.cargo-checksum.json b/vendor/ecdsa/.cargo-checksum.json new file mode 100644 index 0000000..ad97475 --- /dev/null +++ b/vendor/ecdsa/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"}
\ No newline at end of file diff --git a/vendor/ecdsa/CHANGELOG.md b/vendor/ecdsa/CHANGELOG.md new file mode 100644 index 0000000..1790e5b --- /dev/null +++ b/vendor/ecdsa/CHANGELOG.md @@ -0,0 +1,582 @@ +# Changelog +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.8 (2023-07-20) +### Added +- `hazmat::{sign_prehashed, verify_prehashed}` ([#731]) + +### Changed +- Refactor `Signature` constructors and improve docs ([#730]) + +[#730]: https://github.com/RustCrypto/signatures/pull/730 +[#731]: https://github.com/RustCrypto/signatures/pull/731 + +## 0.16.7 (2023-05-11) +### Added +- RFC5480 citation for `der::Signature` ([#710]) +- support for the `SignatureBitStringEncoding` trait ([#716]) + +### Changed +- bump `elliptic-curve` from 0.13.3 to 0.13.4 ([#709]) +- `der::Signature` citation to RFC5912 ([#711]) +- make `fmt` impls more consistent ([#713]) + +### Fixed +- `serde` doc fixup ([#712]) + +[#709]: https://github.com/RustCrypto/signatures/pull/709 +[#710]: https://github.com/RustCrypto/signatures/pull/710 +[#711]: https://github.com/RustCrypto/signatures/pull/711 +[#712]: https://github.com/RustCrypto/signatures/pull/712 +[#713]: https://github.com/RustCrypto/signatures/pull/713 +[#716]: https://github.com/RustCrypto/signatures/pull/716 + +## 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]) + +### Fixed +- Prehash must receive zero-pads on left ([#547]) + +[#547]: https://github.com/RustCrypto/signatures/pull/547 +[#548]: https://github.com/RustCrypto/signatures/pull/548 + +## 0.14.7 (2022-09-15) +### Changed +- Relax `Keypair` bounds ([#539]) + +[#539]: https://github.com/RustCrypto/signatures/pull/539 + +## 0.14.6 (2022-09-12) +### Added +- Impl `signature::hazmat::{PrehashSigner, PrehashVerifier}` ([#534]) +- Impl `signature::Keypair` for `SigningKey` ([#535]) + +[#534]: https://github.com/RustCrypto/signatures/pull/534 +[#535]: https://github.com/RustCrypto/signatures/pull/535 + +## 0.14.5 (2022-09-06) +### Added +- Impl `EncodePrivateKey` for `SigningKey` ([#523]) +- `SigningKey::as_nonzero_scalar` ([#528]) +- `VerifyingKey::as_affine` ([#528]) +- `RecoveryId::from_byte` ([#531]) + +### Changed +- Make `RecoveryId` methods `const fn` ([#529]) + +[#523]: https://github.com/RustCrypto/signatures/pull/523 +[#528]: https://github.com/RustCrypto/signatures/pull/528 +[#529]: https://github.com/RustCrypto/signatures/pull/529 +[#531]: https://github.com/RustCrypto/signatures/pull/531 + +## 0.14.4 (2022-08-15) +### Added +- Impl `EncodePublicKey` for `VerifyingKey` ([#505]) +- ZeroizeOnDrop marker for SigningKey ([#509]) + +### Changed +- Restrict `signature` version to v1.5-v1.6 ([#508], [#512]) + +[#505]: https://github.com/RustCrypto/signatures/pull/505 +[#508]: https://github.com/RustCrypto/signatures/pull/508 +[#509]: https://github.com/RustCrypto/signatures/pull/509 +[#512]: https://github.com/RustCrypto/signatures/pull/512 + +## 0.14.3 (2022-06-26) [YANKED] +### Changed +- Simplified digest trait bounds ([#499]) +- Bump `rfc6979` dependency to v0.3 ([#500]) + +[#499]: https://github.com/RustCrypto/signatures/pull/499 +[#500]: https://github.com/RustCrypto/signatures/pull/500 + +## 0.14.2 (2022-06-17) [YANKED] +### Added +- Security warning in README.md ([#486]) + +### Changed +- Use `serdect` for `Signature` types ([#497]) + +[#486]: https://github.com/RustCrypto/signatures/pull/486 +[#497]: https://github.com/RustCrypto/signatures/pull/497 + +## 0.14.1 (2022-05-09) [YANKED] +### Added +- `SignPrimitive::try_sign_digest_rfc6979` ([#475]) +- `VerifyPrimitive::verify_digest` ([#475]) + +[#475]: https://github.com/RustCrypto/signatures/pull/475 + +## 0.14.0 (2022-05-09) [YANKED] +### Added +- `VerifyingKey::from_affine` ([#452]) + +### Changed +- Bump `digest` dependency to v0.10 ([#433]) +- `SignPrimitive` and `VerifyPrimitive` to accept `FieldBytes<C>` rather than `Scalar<C>` ([#460]) +- Replace `hazmat::rfc6979_generate_k` with `SignPrimitive::try_sign_prehashed_rfc6979` ([#460]) +- Bump `der` dependency to v0.6 ([#468]) +- Bump `elliptic-curve` dependency to v0.12 ([#468]) +- Bump `rfc6979` dependency to v0.2 ([#470]) + +[#433]: https://github.com/RustCrypto/signatures/pull/433 +[#452]: https://github.com/RustCrypto/signatures/pull/452 +[#460]: https://github.com/RustCrypto/signatures/pull/460 +[#468]: https://github.com/RustCrypto/signatures/pull/468 +[#470]: https://github.com/RustCrypto/signatures/pull/470 + +## 0.13.4 (2022-01-06) +### Added +- `Signature::to_vec` ([#428]) + +[#428]: https://github.com/RustCrypto/signatures/pull/428 + +## 0.13.3 (2021-12-04) +### Changed +- Use revised `LinearCombination` trait ([#419]) + +[#419]: https://github.com/RustCrypto/signatures/pull/419 + +## 0.13.2 (2021-12-04) [YANKED] +### Changed +- Use `LinearCombination` trait ([#417]) + +[#417]: https://github.com/RustCrypto/signatures/pull/417 + +## 0.13.1 (2021-12-03) [YANKED] +### Added +- `hazmat::rfc6979_generate_k` function ([#414]) + +[#414]: https://github.com/RustCrypto/signatures/pull/414 + +## 0.13.0 (2021-11-21) [YANKED] +### Added +- `RecoveryId` type ([#392]) +- Default generic impl of `SignPrimitive::try_sign_prehashed` ([#396]) +- Default generic impl of `VerifyPrimitive::verify_prehashed` ([#397]) +- `serde` support ([#406]) + +### Changed +- Make `Signature::normalize_s` non-mutating ([#355]) +- Switch from `ScalarBytes<C>` to `ScalarCore<C>` ([#356]) +- Use `PrimeCurve` trait ([#357]) +- Replace `FromDigest` trait with `Reduce` ([#372]) +- 2021 edition upgrade; MSRV 1.56 ([#384]) +- Allow `signature` v1.4 as a dependency ([#385]) +- Bump `der` dependency to v0.5 ([#408]) +- Bump `elliptic-curve` dependency to v0.11 ([#408]) +- Split out `rfc6979` crate ([#409]) + +### Removed +- `NormalizeLow` trait ([#393]) +- `RecoverableSignPrimitive` ([#394]) + +[#355]: https://github.com/RustCrypto/signatures/pull/355 +[#356]: https://github.com/RustCrypto/signatures/pull/356 +[#357]: https://github.com/RustCrypto/signatures/pull/357 +[#372]: https://github.com/RustCrypto/signatures/pull/372 +[#384]: https://github.com/RustCrypto/signatures/pull/384 +[#385]: https://github.com/RustCrypto/signatures/pull/385 +[#392]: https://github.com/RustCrypto/signatures/pull/392 +[#393]: https://github.com/RustCrypto/signatures/pull/393 +[#394]: https://github.com/RustCrypto/signatures/pull/394 +[#396]: https://github.com/RustCrypto/signatures/pull/396 +[#397]: https://github.com/RustCrypto/signatures/pull/397 +[#406]: https://github.com/RustCrypto/signatures/pull/406 +[#408]: https://github.com/RustCrypto/signatures/pull/408 +[#409]: https://github.com/RustCrypto/signatures/pull/409 + +## 0.12.4 (2021-08-12) +### Added +- Impl `Clone`, `Debug`, `*Eq` for `SigningKey` ([#345]) + +[#345]: https://github.com/RustCrypto/signatures/pull/345 + +## 0.12.3 (2021-06-17) +### Added +- Impl `TryFrom<&[u8]>` for `Verifying<C>` ([#329]) +- Impl `TryFrom<&[u8]>` for `SigningKey<C>` ([#330]) + +### Changed +- Use `signature::Result` alias ([#331]) + +[#329]: https://github.com/RustCrypto/signatures/pull/329 +[#330]: https://github.com/RustCrypto/signatures/pull/330 +[#331]: https://github.com/RustCrypto/signatures/pull/331 + +## 0.12.2 (2021-06-18) +### Added +- Zeroization on drop for `SigningKey` ([#321]) + +[#321]: https://github.com/RustCrypto/signatures/pull/321 + +## 0.12.1 (2021-06-09) +### Added +- Explicit `Copy` bounds on `VerifyingKey` ([#318]) + +[#318]: https://github.com/RustCrypto/signatures/pull/318 + +## 0.12.0 (2021-06-07) +### Changed +- Bump `der` crate to v0.4 ([#302], [#315]) +- Bump `elliptic-curve` crate dependency to v0.10 ([#315]) +- MSRV 1.51+ ([#302], [#315]) + +### Removed +- Bounds now expressed via `*Arithmetic` traits ([#303], [#312]) + +[#302]: https://github.com/RustCrypto/signatures/pull/302 +[#303]: https://github.com/RustCrypto/signatures/pull/303 +[#315]: https://github.com/RustCrypto/signatures/pull/315 + +## 0.11.1 (2021-05-24) +### Added +- `Ord` and `PartialOrd` impls on VerifyingKey ([#298], [#299]) + +### Changed +- Bump `elliptic-curve` dependency to v0.9.12 ([#299]) + +[#298]: https://github.com/RustCrypto/signatures/pull/298 +[#299]: https://github.com/RustCrypto/signatures/pull/299 + +## 0.11.0 (2021-04-29) +### Added +- `FromDigest` trait ([#238], [#244]) +- Wycheproof test vector support ([#260]) + +### Changed +- Use `der` crate for decoding/encoding signatures ([#226], [#267]) +- Support `HmacDrbg` with variable output size ([#243]) +- Bump `base64ct` and `pkcs8`; MSRV 1.47+ ([#262]) +- Flatten and simplify public API ([#268]) +- Use `verifying_key` name consistently ([#273]) +- Bound curve implementations on Order trait ([#280]) +- Bump `elliptic-curve` to v0.9.10+; use `ScalarBytes` ([#284]) +- Bump `hmac` crate dependency to v0.11 ([#287]) + +### Removed +- `FieldBytes` bounds ([#227]) +- `CheckSignatureBytes` trait ([#281]) + +[#226]: https://github.com/RustCrypto/signatures/pull/226 +[#227]: https://github.com/RustCrypto/signatures/pull/227 +[#238]: https://github.com/RustCrypto/signatures/pull/238 +[#243]: https://github.com/RustCrypto/signatures/pull/243 +[#244]: https://github.com/RustCrypto/signatures/pull/244 +[#260]: https://github.com/RustCrypto/signatures/pull/260 +[#262]: https://github.com/RustCrypto/signatures/pull/262 +[#267]: https://github.com/RustCrypto/signatures/pull/267 +[#268]: https://github.com/RustCrypto/signatures/pull/268 +[#273]: https://github.com/RustCrypto/signatures/pull/273 +[#280]: https://github.com/RustCrypto/signatures/pull/280 +[#281]: https://github.com/RustCrypto/signatures/pull/281 +[#284]: https://github.com/RustCrypto/signatures/pull/284 +[#287]: https://github.com/RustCrypto/signatures/pull/287 + +## 0.10.2 (2020-12-22) +### Changed +- Bump `elliptic-curve` crate to v0.8.3 ([#218]) +- Use the `dev` module from the `elliptic-curve` crate ([#218]) + +[#218]: https://github.com/RustCrypto/signatures/pull/218 + +## 0.10.1 (2020-12-16) [YANKED] +### Fixed +- Trigger docs.rs rebuild with nightly bugfix ([RustCrypto/traits#412]) + +[RustCrypto/traits#412]: https://github.com/RustCrypto/traits/pull/412 + +## 0.10.0 (2020-12-16) [YANKED] +### Changed +- Bump `elliptic-curve` dependency to v0.8 ([#215]) + +[#215]: https://github.com/RustCrypto/signatures/pull/215 + +## 0.9.0 (2020-12-06) +### Added +- PKCS#8 support ([#203]) + +### Changed +- Bump `elliptic-curve` crate dependency to v0.7; MSRV 1.46+ ([#204]) +- Rename `VerifyKey` to `VerifyingKey` ([#200]) +- Rename `VerifyingKey::new()` to `::from_sec1_bytes()` ([#198]) +- Rename `SigningKey::new()` to `::from_bytes()` ([#205]) + +### Fixed +- Additional validity checks on ASN.1 DER-encoded signatures ([#192]) + +[#205]: https://github.com/RustCrypto/signatures/pull/205 +[#204]: https://github.com/RustCrypto/signatures/pull/204 +[#203]: https://github.com/RustCrypto/signatures/pull/203 +[#200]: https://github.com/RustCrypto/signatures/pull/200 +[#198]: https://github.com/RustCrypto/signatures/pull/198 +[#192]: https://github.com/RustCrypto/signatures/pull/192 + +## 0.8.5 (2020-10-09) +### Fixed +- Bug in default impl of CheckSignatureBytes ([#184]) + +[#184]: https://github.com/RustCrypto/signatures/pull/184 + +## 0.8.4 (2020-10-08) +### Fixed +- Work around `nightly-2020-10-06` breakage ([#180]) + +[#180]: https://github.com/RustCrypto/signatures/pull/180 + +## 0.8.3 (2020-09-28) +### Fixed +- 32-bit builds for the `dev` feature ([#177]) + +[#177]: https://github.com/RustCrypto/signatures/pull/177 + +## 0.8.2 (2020-09-27) +### Added +- `RecoverableSignPrimitive` ([#174], [#175]) + +[#174]: https://github.com/RustCrypto/signatures/pull/174 +[#175]: https://github.com/RustCrypto/signatures/pull/175 + +## 0.8.1 (2020-09-23) +### Added +- Conditional `Copy` impl on `VerifyKey<C>` ([#171]) + +[#171]: https://github.com/RustCrypto/signatures/pull/171 + +## 0.8.0 (2020-09-11) +### Added +- `CheckSignatureBytes` trait ([#151]) +- Add `Signature::r`/`::s` methods which return `NonZeroScalar`values ([#151]) +- `alloc` feature ([#150]) +- Impl `From<&VerifyKey<C>>` for `EncodedPoint<C>` ([#144]) +- Serialization methods for `SigningKey`/`VerifyKey` ([#143]) +- RFC6979-based deterministic signatures ([#133], [#134], [#136]) + +### Changed +- Bump `elliptic-curve` crate dependency to v0.6 ([#165]) +- Use `ProjectiveArithmetic` trait ([#164]) +- Rename `ElementBytes` to `FieldBytes` ([#160]) +- Use `ff` and `group` crates to v0.8 ([#156]) +- MSRV 1.44+ ([#156]) +- Remove `rand` feature; make `rand_core` a hard dependency ([#154]) +- Use `impl Into<ElementBytes>` bounds on `Signature::from_scalars` ([#149]) +- Derive `Clone`, `Debug`, `Eq`, and `Ord` on `VerifyKey` ([#148]) +- Renamed `{Signer, Verifier}` => `{SigningKey, VerifyKey}` ([#140]) +- Use newly refactored `sec1::EncodedPoint` ([#131]) + +### Removed +- `Generate` trait ([#159]) +- `RecoverableSignPrimitive` ([#146]) + +[#165]: https://github.com/RustCrypto/signatures/pull/165 +[#164]: https://github.com/RustCrypto/signatures/pull/164 +[#160]: https://github.com/RustCrypto/signatures/pull/160 +[#159]: https://github.com/RustCrypto/signatures/pull/159 +[#156]: https://github.com/RustCrypto/signatures/pull/156 +[#154]: https://github.com/RustCrypto/signatures/pull/154 +[#151]: https://github.com/RustCrypto/signatures/pull/151 +[#150]: https://github.com/RustCrypto/signatures/pull/150 +[#149]: https://github.com/RustCrypto/signatures/pull/149 +[#148]: https://github.com/RustCrypto/signatures/pull/148 +[#146]: https://github.com/RustCrypto/signatures/pull/146 +[#144]: https://github.com/RustCrypto/signatures/pull/144 +[#143]: https://github.com/RustCrypto/signatures/pull/143 +[#140]: https://github.com/RustCrypto/signatures/pull/140 +[#136]: https://github.com/RustCrypto/signatures/pull/136 +[#134]: https://github.com/RustCrypto/signatures/pull/134 +[#133]: https://github.com/RustCrypto/signatures/pull/133 +[#131]: https://github.com/RustCrypto/signatures/pull/131 + +## 0.7.2 (2020-08-11) +### Added +- Conditional `PrehashSignature` impl for `asn1::Signature` ([#128]) + +[#128]: https://github.com/RustCrypto/signatures/pull/128 + +## 0.7.1 (2020-08-10) +### Changed +- Use `all-features = true` on docs.rs ([#126]) + +[#126]: https://github.com/RustCrypto/signatures/pull/126 + +## 0.7.0 (2020-08-10) +### Added +- `hazmat` traits: `SignPrimitive`, `RecoverableSignPrimitive`, + `VerifyPrimitive`, `DigestPrimitive` ([#96], [#99], [#107], [#111]) +- `dev` module ([#103]) +- `NormalizeLow` trait ([#115], [#118], [#119]) +- `Copy` impl on `Signature` ([#117]) +- `RecoverableSignPrimitive` ([#120]) + +### Changed +- Bumped `elliptic-curve` crate to v0.5 release ([#123]) +- Renamed `FixedSignature` to `ecdsa::Signature` ([#98]) +- Renamed `Asn1Signature` to `ecdsa::asn1::Signature` ([#98], [#102]) + +### Removed +- Curve-specific types - migrated to `k256`, `p256`, `p384` crates ([#96]) + +[#96]: https://github.com/RustCrypto/signatures/pull/96 +[#98]: https://github.com/RustCrypto/signatures/pull/98 +[#99]: https://github.com/RustCrypto/signatures/pull/99 +[#102]: https://github.com/RustCrypto/signatures/pull/102 +[#103]: https://github.com/RustCrypto/signatures/pull/103 +[#107]: https://github.com/RustCrypto/signatures/pull/107 +[#111]: https://github.com/RustCrypto/signatures/pull/111 +[#115]: https://github.com/RustCrypto/signatures/pull/115 +[#117]: https://github.com/RustCrypto/signatures/pull/117 +[#118]: https://github.com/RustCrypto/signatures/pull/118 +[#119]: https://github.com/RustCrypto/signatures/pull/119 +[#120]: https://github.com/RustCrypto/signatures/pull/120 +[#123]: https://github.com/RustCrypto/signatures/pull/123 + +## 0.6.1 (2020-06-29) +### Added +- `doc_cfg` attributes for https://docs.rs ([#91]) +- `ecdsa::curve::secp256k1::RecoverableSignature` ([#90]) + +[#91]: https://github.com/RustCrypto/signatures/pull/91 +[#90]: https://github.com/RustCrypto/signatures/pull/90 + +## 0.6.0 (2020-06-09) +### Changed +- Upgrade to `signature` ~1.1.0; `sha` v0.9 ([#87]) +- Bump all elliptic curve crates; MSRV 1.41+ ([#86]) + +[#87]: https://github.com/RustCrypto/signatures/pull/87 +[#86]: https://github.com/RustCrypto/signatures/pull/86 + +## 0.5.0 (2020-04-18) +### Changed +- Upgrade `signature` crate to v1.0 final release ([#80]) + +[#80]: https://github.com/RustCrypto/signatures/pull/80 + +## 0.4.0 (2020-01-07) +### Changed +- Upgrade `elliptic-curve` crate to v0.3.0; make curves cargo features ([#68]) + +[#68]: https://github.com/RustCrypto/signatures/pull/68 + +## 0.3.0 (2019-12-11) +### Changed +- Upgrade `elliptic-curve` crate to v0.2.0; MSRV 1.37+ ([#65]) + +[#65]: https://github.com/RustCrypto/signatures/pull/65 + +## 0.2.1 (2019-12-06) +### Added +- Re-export `PublicKey` and `SecretKey` from the `elliptic-curve` crate ([#61]) + +[#61]: https://github.com/RustCrypto/signatures/pull/61 + +## 0.2.0 (2019-12-06) +### Changed +- Use curve types from the `elliptic-curve` crate ([#58]) + +[#58]: https://github.com/RustCrypto/signatures/pull/58 + +## 0.1.0 (2019-10-29) + +- Initial release diff --git a/vendor/ecdsa/Cargo.toml b/vendor/ecdsa/Cargo.toml new file mode 100644 index 0000000..9e2678d --- /dev/null +++ b/vendor/ecdsa/Cargo.toml @@ -0,0 +1,148 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "ecdsa" +version = "0.16.8" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of the Elliptic Curve Digital Signature Algorithm +(ECDSA) as specified in FIPS 186-4 (Digital Signature Standard), providing +RFC6979 deterministic signatures as well as support for added entropy +""" +readme = "README.md" +keywords = [ + "crypto", + "ecc", + "nist", + "secp256k1", + "signature", +] +categories = [ + "cryptography", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/signatures/tree/master/ecdsa" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.der] +version = "0.7" +optional = true + +[dependencies.digest] +version = "0.10.7" +features = ["oid"] +optional = true +default-features = false + +[dependencies.elliptic-curve] +version = "0.13.5" +features = [ + "digest", + "sec1", +] +default-features = false + +[dependencies.rfc6979] +version = "0.4" +optional = true + +[dependencies.serdect] +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 = "2.1" +features = ["rand_core"] +default-features = false + +[dependencies.spki] +version = "0.7.2" +optional = true +default-features = false + +[dev-dependencies.elliptic-curve] +version = "0.13" +features = ["dev"] +default-features = false + +[dev-dependencies.hex-literal] +version = "0.4" + +[dev-dependencies.sha2] +version = "0.10" +default-features = false + +[features] +alloc = [ + "elliptic-curve/alloc", + "signature/alloc", + "spki/alloc", +] +arithmetic = ["elliptic-curve/arithmetic"] +default = ["digest"] +dev = [ + "arithmetic", + "digest", + "elliptic-curve/dev", + "hazmat", +] +digest = [ + "dep:digest", + "signature/digest", +] +hazmat = [] +pem = [ + "elliptic-curve/pem", + "pkcs8", +] +pkcs8 = [ + "digest", + "elliptic-curve/pkcs8", + "der", +] +serde = [ + "elliptic-curve/serde", + "serdect", +] +signing = [ + "arithmetic", + "digest", + "hazmat", + "rfc6979", +] +std = [ + "alloc", + "elliptic-curve/std", + "signature/std", +] +verifying = [ + "arithmetic", + "digest", + "hazmat", +] diff --git a/vendor/ecdsa/LICENSE-APACHE b/vendor/ecdsa/LICENSE-APACHE new file mode 100644 index 0000000..c394d8a --- /dev/null +++ b/vendor/ecdsa/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2018-2022 RustCrypto Developers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/ecdsa/LICENSE-MIT b/vendor/ecdsa/LICENSE-MIT new file mode 100644 index 0000000..81a3d57 --- /dev/null +++ b/vendor/ecdsa/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018-2022 RustCrypto Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/ecdsa/README.md b/vendor/ecdsa/README.md new file mode 100644 index 0000000..06ed0dc --- /dev/null +++ b/vendor/ecdsa/README.md @@ -0,0 +1,93 @@ +# [RustCrypto]: ECDSA + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![MSRV][rustc-image] +[![Project Chat][chat-image]][chat-link] + +[Elliptic Curve Digital Signature Algorithm (ECDSA)][1] as specified in +[FIPS 186-4][2] (Digital Signature Standard). + +[Documentation][docs-link] + +## About + +This crate provides generic ECDSA support which can be used in the following +ways: + +- Generic implementation of ECDSA usable with the following crates: + - [`k256`] (secp256k1) + - [`p256`] (NIST P-256) + - [`p384`] (NIST P-384) +- Other crates which provide their own complete implementations of ECDSA can + also leverage the types from this crate to export ECDSA functionality in a + generic, interoperable way by leveraging [`ecdsa::Signature`] with the + [`signature::Signer`] and [`signature::Verifier`] traits. + +## ⚠️ Security Warning + +The ECDSA implementation contained in this crate has never been independently +audited for security! + +This crate contains a generic implementation of ECDSA which must be +instantiated using a separate crate providing a concrete implementation of +arithmetic for a particular curve. It's possible timing variability can exist +in concrete curve implementations, and thus this crate's security can only be +properly assessed for a specific elliptic curve. + +USE AT YOUR OWN RISK! + +## Minimum Supported Rust Version + +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. + +## License + +All crates licensed under either of + +- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) +- [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/ecdsa +[crate-link]: https://crates.io/crates/ecdsa +[docs-image]: https://docs.rs/ecdsa/badge.svg +[docs-link]: https://docs.rs/ecdsa/ +[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.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 + +[//]: # (links) + +[RustCrypto]: https://github.com/RustCrypto + +[//]: # (footnotes) + +[1]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +[2]: https://csrc.nist.gov/publications/detail/fips/186/4/final + +[//]: # (docs.rs definitions) + +[`ecdsa::Signature`]: https://docs.rs/ecdsa/latest/ecdsa/struct.Signature.html +[`k256`]: https://docs.rs/k256 +[`p256`]: https://docs.rs/p256 +[`p384`]: https://docs.rs/p384 +[`signature::Signer`]: https://docs.rs/signature/latest/signature/trait.Signer.html +[`signature::Verifier`]: https://docs.rs/signature/latest/signature/trait.Verifier.html diff --git a/vendor/ecdsa/debian/patches/fix-signature-dep.patch b/vendor/ecdsa/debian/patches/fix-signature-dep.patch new file mode 100644 index 0000000..64b34c0 --- /dev/null +++ b/vendor/ecdsa/debian/patches/fix-signature-dep.patch @@ -0,0 +1,13 @@ +Index: ecdsa/Cargo.toml +=================================================================== +--- ecdsa.orig/Cargo.toml ++++ ecdsa/Cargo.toml +@@ -77,7 +77,7 @@ optional = true + default-features = false + + [dependencies.signature] +-version = "2.0, <2.2" ++version = "2.1" + features = ["rand_core"] + default-features = false + diff --git a/vendor/ecdsa/debian/patches/series b/vendor/ecdsa/debian/patches/series new file mode 100644 index 0000000..eae00f7 --- /dev/null +++ b/vendor/ecdsa/debian/patches/series @@ -0,0 +1 @@ +fix-signature-dep.patch diff --git a/vendor/ecdsa/src/der.rs b/vendor/ecdsa/src/der.rs new file mode 100644 index 0000000..b4b03c1 --- /dev/null +++ b/vendor/ecdsa/src/der.rs @@ -0,0 +1,464 @@ +//! Support for ASN.1 DER-encoded ECDSA signatures as specified in +//! [RFC5912 Appendix A]. +//! +//! [RFC5912 Appendix A]: https://www.rfc-editor.org/rfc/rfc5912#appendix-A + +use crate::{Error, Result}; +use core::{ + fmt::{self, Debug}, + ops::{Add, Range}, +}; +use der::{asn1::UintRef, Decode, Encode, FixedTag, Length, Reader, Tag, Writer}; +use elliptic_curve::{ + consts::U9, + generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, + FieldBytesSize, PrimeCurve, +}; + +#[cfg(feature = "alloc")] +use { + alloc::{boxed::Box, vec::Vec}, + signature::SignatureEncoding, + spki::{der::asn1::BitString, SignatureBitStringEncoding}, +}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Maximum overhead of an ASN.1 DER-encoded ECDSA signature for a given curve: +/// 9-bytes. +/// +/// Includes 3-byte ASN.1 DER header: +/// +/// - 1-byte: ASN.1 `SEQUENCE` tag (0x30) +/// - 2-byte: length +/// +/// ...followed by two ASN.1 `INTEGER` values, which each have a header whose +/// maximum length is the following: +/// +/// - 1-byte: ASN.1 `INTEGER` tag (0x02) +/// - 1-byte: length +/// - 1-byte: zero to indicate value is positive (`INTEGER` is signed) +pub type MaxOverhead = U9; + +/// Maximum size of an ASN.1 DER encoded signature for the given elliptic curve. +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>>; + +/// ASN.1 DER-encoded signature as specified in [RFC5912 Appendix A]: +/// +/// ```text +/// ECDSA-Sig-Value ::= SEQUENCE { +/// r INTEGER, +/// s INTEGER +/// } +/// ``` +/// +/// [RFC5912 Appendix A]: https://www.rfc-editor.org/rfc/rfc5912#appendix-A +pub struct Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + /// ASN.1 DER-encoded signature data + bytes: SignatureBytes<C>, + + /// Range of the `r` value within the signature + r_range: Range<usize>, + + /// Range of the `s` value within the signature + s_range: Range<usize>, +} + +#[allow(clippy::len_without_is_empty)] +impl<C> Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + /// Parse signature from DER-encoded bytes. + pub fn from_bytes(input: &[u8]) -> Result<Self> { + let (r, s) = decode_der(input).map_err(|_| Error::new())?; + + if r.as_bytes().len() > C::FieldBytesSize::USIZE + || s.as_bytes().len() > C::FieldBytesSize::USIZE + { + return Err(Error::new()); + } + + let r_range = find_scalar_range(input, r.as_bytes())?; + let s_range = find_scalar_range(input, s.as_bytes())?; + + if s_range.end != input.len() { + return Err(Error::new()); + } + + let mut bytes = SignatureBytes::<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` 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); + + writer.sequence((r.encoded_len()? + s.encoded_len()?)?, |seq| { + seq.encode(&r)?; + seq.encode(&s) + })?; + + writer + .finish()? + .try_into() + .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()] + } + + /// Get the `s` component of the signature (leading zeros removed) + pub(crate) fn s(&self) -> &[u8] { + &self.bytes[self.s_range.clone()] + } +} + +impl<C> AsRef<[u8]> for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +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>, + <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())?; + + for &byte in self.as_ref() { + write!(f, "{:02X}", byte)?; + } + + write!(f, ")") + } +} + +impl<'a, C> Decode<'a> for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> { + let header = reader.peek_header()?; + header.tag.assert_eq(Tag::Sequence)?; + + 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()))?; + + reader.read_into(slice)?; + Self::from_bytes(slice).map_err(|_| Tag::Integer.value_error()) + } +} + +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()) + } + + fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { + writer.write(self.as_bytes()) + } +} + +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; +} + +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 crate::Signature<C> +where + C: PrimeCurve, + MaxSize<C>: 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::FieldBytesSize::USIZE.saturating_sub(sig.r().len()); + let s_begin = bytes.len().saturating_sub(sig.s().len()); + 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 = "alloc")] +impl<C> SignatureBitStringEncoding for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + fn to_bitstring(&self) -> der::Result<BitString> { + BitString::new(0, self.to_vec()) + } +} + +#[cfg(feature = "serde")] +impl<C> Serialize for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: 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 + S: ser::Serializer, + { + serdect::slice::serialize_hex_upper_or_bin(&self.as_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for Signature<C> +where + C: PrimeCurve, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + let mut buf = SignatureBytes::<C>::default(); + let slice = serdect::slice::deserialize_hex_or_bin(&mut buf, deserializer)?; + Self::try_from(slice).map_err(de::Error::custom) + } +} + +/// Decode the `r` and `s` components of a DER-encoded ECDSA signature. +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)?; + Ok((r, s)) + })?; + + reader.finish(ret) +} + +/// Locate the range within a slice at which a particular subslice is located +fn find_scalar_range(outer: &[u8], inner: &[u8]) -> Result<Range<usize>> { + let outer_start = outer.as_ptr() as usize; + let inner_start = inner.as_ptr() as usize; + let start = inner_start + .checked_sub(outer_start) + .ok_or_else(Error::new)?; + let end = start.checked_add(inner.len()).ok_or_else(Error::new)?; + Ok(Range { start, end }) +} + +#[cfg(all(feature = "digest", feature = "hazmat"))] +impl<C> signature::PrehashSignature for Signature<C> +where + C: PrimeCurve + crate::hazmat::DigestPrimitive, + MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, +{ + type Digest = C::Digest; +} + +#[cfg(all(test, feature = "arithmetic"))] +mod tests { + use elliptic_curve::dev::MockCurve; + + type Signature = crate::Signature<MockCurve>; + + const EXAMPLE_SIGNATURE: [u8; 64] = [ + 0xf3, 0xac, 0x80, 0x61, 0xb5, 0x14, 0x79, 0x5b, 0x88, 0x43, 0xe3, 0xd6, 0x62, 0x95, 0x27, + 0xed, 0x2a, 0xfd, 0x6b, 0x1f, 0x6a, 0x55, 0x5a, 0x7a, 0xca, 0xbb, 0x5e, 0x6f, 0x79, 0xc8, + 0xc2, 0xac, 0x8b, 0xf7, 0x78, 0x19, 0xca, 0x5, 0xa6, 0xb2, 0x78, 0x6c, 0x76, 0x26, 0x2b, + 0xf7, 0x37, 0x1c, 0xef, 0x97, 0xb2, 0x18, 0xe9, 0x6f, 0x17, 0x5a, 0x3c, 0xcd, 0xda, 0x2a, + 0xcc, 0x5, 0x89, 0x3, + ]; + + #[test] + fn test_fixed_to_asn1_signature_roundtrip() { + let signature1 = Signature::try_from(EXAMPLE_SIGNATURE.as_ref()).unwrap(); + + // Convert to ASN.1 DER and back + let asn1_signature = signature1.to_der(); + let signature2 = Signature::from_der(asn1_signature.as_ref()).unwrap(); + + assert_eq!(signature1, signature2); + } + + #[test] + fn test_asn1_too_short_signature() { + assert!(Signature::from_der(&[]).is_err()); + assert!(Signature::from_der(&[der::Tag::Sequence.into()]).is_err()); + assert!(Signature::from_der(&[der::Tag::Sequence.into(), 0x00]).is_err()); + assert!(Signature::from_der(&[ + der::Tag::Sequence.into(), + 0x03, + der::Tag::Integer.into(), + 0x01, + 0x01 + ]) + .is_err()); + } + + #[test] + fn test_asn1_non_der_signature() { + // A minimal 8-byte ASN.1 signature parses OK. + assert!(Signature::from_der(&[ + der::Tag::Sequence.into(), + 0x06, // length of below + der::Tag::Integer.into(), + 0x01, // length of value + 0x01, // value=1 + der::Tag::Integer.into(), + 0x01, // length of value + 0x01, // value=1 + ]) + .is_ok()); + + // But length fields that are not minimally encoded should be rejected, as they are not + // valid DER, cf. + // https://github.com/google/wycheproof/blob/2196000605e4/testvectors/ecdsa_secp256k1_sha256_test.json#L57-L66 + assert!(Signature::from_der(&[ + der::Tag::Sequence.into(), + 0x81, // extended length: 1 length byte to come + 0x06, // length of below + der::Tag::Integer.into(), + 0x01, // length of value + 0x01, // value=1 + der::Tag::Integer.into(), + 0x01, // length of value + 0x01, // value=1 + ]) + .is_err()); + } +} diff --git a/vendor/ecdsa/src/dev.rs b/vendor/ecdsa/src/dev.rs new file mode 100644 index 0000000..8c1b7c8 --- /dev/null +++ b/vendor/ecdsa/src/dev.rs @@ -0,0 +1,230 @@ +//! Development-related functionality. + +// TODO(tarcieri): implement full set of tests from ECDSA2VS +// <https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/dss2/ecdsa2vs.pdf> + +/// ECDSA test vector +pub struct TestVector { + /// Private scalar + pub d: &'static [u8], + + /// Public key x-coordinate (`Qx`) + pub q_x: &'static [u8], + + /// Public key y-coordinate (`Qy`) + pub q_y: &'static [u8], + + /// Ephemeral scalar (a.k.a. nonce) + pub k: &'static [u8], + + /// Message digest (prehashed) + pub m: &'static [u8], + + /// Signature `r` component + pub r: &'static [u8], + + /// Signature `s` component + pub s: &'static [u8], +} + +/// Define ECDSA signing test. +#[macro_export] +macro_rules! new_signing_test { + ($curve:path, $vectors:expr) => { + use $crate::{ + elliptic_curve::{ + 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>::FieldBytesSize::USIZE { + Scalar::<$curve>::from_repr(GenericArray::clone_from_slice(bytes)).into() + } else { + None + } + } + + #[test] + fn ecdsa_signing() { + 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; + + assert_eq!(vector.r, sig.r().to_bytes().as_slice()); + assert_eq!(vector.s, sig.s().to_bytes().as_slice()); + } + } + }; +} + +/// Define ECDSA verification test. +#[macro_export] +macro_rules! new_verification_test { + ($curve:path, $vectors:expr) => { + use $crate::{ + elliptic_curve::{ + generic_array::GenericArray, + group::ff::PrimeField, + sec1::{EncodedPoint, FromEncodedPoint}, + AffinePoint, CurveArithmetic, Scalar, + }, + hazmat::VerifyPrimitive, + Signature, + }; + + #[test] + fn ecdsa_verify_success() { + for vector in $vectors { + let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates( + GenericArray::from_slice(vector.q_x), + GenericArray::from_slice(vector.q_y), + false, + ); + + let q = AffinePoint::<$curve>::from_encoded_point(&q_encoded).unwrap(); + let z = GenericArray::clone_from_slice(vector.m); + + let sig = Signature::from_scalars( + GenericArray::clone_from_slice(vector.r), + GenericArray::clone_from_slice(vector.s), + ) + .unwrap(); + + let result = q.verify_prehashed(&z, &sig); + assert!(result.is_ok()); + } + } + + #[test] + fn ecdsa_verify_invalid_s() { + for vector in $vectors { + let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates( + GenericArray::from_slice(vector.q_x), + GenericArray::from_slice(vector.q_y), + false, + ); + + let q = AffinePoint::<$curve>::from_encoded_point(&q_encoded).unwrap(); + let z = GenericArray::clone_from_slice(vector.m); + + // Flip a bit in `s` + let mut s_tweaked = GenericArray::clone_from_slice(vector.s); + s_tweaked[0] ^= 1; + + let sig = + Signature::from_scalars(GenericArray::clone_from_slice(vector.r), s_tweaked) + .unwrap(); + + let result = q.verify_prehashed(&z, &sig); + assert!(result.is_err()); + } + } + + // TODO(tarcieri): test invalid Q, invalid r, invalid m + }; +} + +/// Define a Wycheproof verification test. +#[macro_export] +macro_rules! new_wycheproof_test { + ($name:ident, $test_name: expr, $curve:path) => { + use $crate::{ + elliptic_curve::{bigint::Integer, sec1::EncodedPoint}, + signature::Verifier, + Signature, + }; + + #[test] + fn $name() { + use blobby::Blob5Iterator; + use elliptic_curve::{bigint::Encoding as _, generic_array::typenum::Unsigned}; + + // Build a field element but allow for too-short input (left pad with zeros) + // or too-long input (check excess leftmost bytes are zeros). + fn element_from_padded_slice<C: elliptic_curve::Curve>( + data: &[u8], + ) -> elliptic_curve::FieldBytes<C> { + let point_len = C::FieldBytesSize::USIZE; + if data.len() >= point_len { + let offset = data.len() - point_len; + for v in data.iter().take(offset) { + assert_eq!(*v, 0, "EcdsaVerifier: point too large"); + } + elliptic_curve::FieldBytes::<C>::clone_from_slice(&data[offset..]) + } else { + // Provided slice is too short and needs to be padded with zeros + // on the left. Build a combined exact iterator to do this. + let iter = core::iter::repeat(0) + .take(point_len - data.len()) + .chain(data.iter().cloned()); + elliptic_curve::FieldBytes::<C>::from_exact_iter(iter).unwrap() + } + } + + fn run_test( + wx: &[u8], + wy: &[u8], + msg: &[u8], + sig: &[u8], + pass: bool, + ) -> Option<&'static str> { + let x = element_from_padded_slice::<$curve>(wx); + let y = element_from_padded_slice::<$curve>(wy); + let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates( + &x, &y, /* compress= */ false, + ); + let verifying_key = + $crate::VerifyingKey::<$curve>::from_encoded_point(&q_encoded).unwrap(); + + let sig = match Signature::from_der(sig) { + Ok(s) => s, + Err(_) if !pass => return None, + Err(_) => return Some("failed to parse signature ASN.1"), + }; + + match verifying_key.verify(msg, &sig) { + Ok(_) if pass => None, + Ok(_) => Some("signature verify unexpectedly succeeded"), + Err(_) if !pass => None, + Err(_) => Some("signature verify failed"), + } + } + + let data = include_bytes!(concat!("test_vectors/data/", $test_name, ".blb")); + + for (i, row) in Blob5Iterator::new(data).unwrap().enumerate() { + let [wx, wy, msg, sig, status] = row.unwrap(); + let pass = match status[0] { + 0 => false, + 1 => true, + _ => panic!("invalid value for pass flag"), + }; + if let Some(desc) = run_test(wx, wy, msg, sig, pass) { + panic!( + "\n\ + Failed test №{}: {}\n\ + wx:\t{:?}\n\ + wy:\t{:?}\n\ + msg:\t{:?}\n\ + sig:\t{:?}\n\ + pass:\t{}\n", + i, desc, wx, wy, msg, sig, pass, + ); + } + } + } + }; +} diff --git a/vendor/ecdsa/src/hazmat.rs b/vendor/ecdsa/src/hazmat.rs new file mode 100644 index 0000000..0f7ddbf --- /dev/null +++ b/vendor/ecdsa/src/hazmat.rs @@ -0,0 +1,332 @@ +//! Low-level ECDSA primitives. +//! +//! # ⚠️ Warning: Hazmat! +//! +//! YOU PROBABLY DON'T WANT TO USE THESE! +//! +//! These primitives are easy-to-misuse low-level interfaces. +//! +//! If you are an end user / non-expert in cryptography, do not use these! +//! 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}, + elliptic_curve::{ + ff::{Field, PrimeField}, + group::{Curve as _, Group}, + ops::{Invert, LinearCombination, MulByGenerator, Reduce}, + point::AffineCoordinates, + scalar::IsHigh, + subtle::CtOption, + CurveArithmetic, ProjectivePoint, Scalar, + }, +}; + +#[cfg(feature = "digest")] +use { + elliptic_curve::FieldBytesSize, + signature::{ + digest::{core_api::BlockSizeUser, Digest, FixedOutput, FixedOutputReset}, + PrehashSignature, + }, +}; + +#[cfg(feature = "rfc6979")] +use elliptic_curve::{FieldBytesEncoding, ScalarPrimitive}; + +#[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")] +pub trait SignPrimitive<C>: + AsRef<Self> + + Into<FieldBytes<C>> + + IsHigh + + PrimeField<Repr = FieldBytes<C>> + + Reduce<C::Uint, Bytes = FieldBytes<C>> + + Sized +where + C: PrimeCurve + CurveArithmetic<Scalar = Self>, + SignatureSize<C>: ArrayLength<u8>, +{ + /// Try to sign the prehashed message. + /// + /// Accepts the following arguments: + /// + /// - `k`: ephemeral scalar value. MUST BE UNIFORMLY RANDOM!!! + /// - `z`: message digest to be signed. MUST BE OUTPUT OF A CRYPTOGRAPHICALLY + /// SECURE DIGEST ALGORITHM!!! + /// + /// # Returns + /// + /// ECDSA [`Signature`] and, when possible/desired, a [`RecoveryId`] + /// which can be used to recover the verifying key for a given signature. + fn try_sign_prehashed<K>( + &self, + k: K, + z: &FieldBytes<C>, + ) -> Result<(Signature<C>, Option<RecoveryId>)> + where + K: AsRef<Self> + Invert<Output = CtOption<Self>>, + { + sign_prehashed(self, k, z).map(|(sig, recid)| (sig, (Some(recid)))) + } + + /// Try to sign the given message digest deterministically using the method + /// described in [RFC6979] for computing ECDSA ephemeral scalar `k`. + /// + /// Accepts the following parameters: + /// - `z`: message digest to be signed. + /// - `ad`: optional additional data, e.g. added entropy from an RNG + /// + /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979 + #[cfg(feature = "rfc6979")] + fn try_sign_prehashed_rfc6979<D>( + &self, + z: &FieldBytes<C>, + ad: &[u8], + ) -> Result<(Signature<C>, Option<RecoveryId>)> + where + Self: From<ScalarPrimitive<C>> + Invert<Output = CtOption<Self>>, + D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldBytesSize<C>> + FixedOutputReset, + { + let k = Scalar::<C>::from_repr(rfc6979::generate_k::<D, _>( + &self.to_repr(), + &C::ORDER.encode_field_bytes(), + z, + ad, + )) + .unwrap(); + + self.try_sign_prehashed::<Self>(k, z) + } +} + +/// Verify the given prehashed message using ECDSA. +/// +/// This trait is intended to be implemented on type which can access +/// the affine point represeting the public key via `&self`, such as a +/// particular curve's `AffinePoint` type. +#[cfg(feature = "arithmetic")] +pub trait VerifyPrimitive<C>: AffineCoordinates<FieldRepr = FieldBytes<C>> + Copy + Sized +where + C: PrimeCurve + CurveArithmetic<AffinePoint = Self>, + SignatureSize<C>: ArrayLength<u8>, +{ + /// Verify the prehashed message against the provided ECDSA signature. + /// + /// Accepts the following arguments: + /// + /// - `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<()> { + verify_prehashed(&ProjectivePoint::<C>::from(*self), z, sig) + } + + /// Verify message digest against the provided signature. + #[cfg(feature = "digest")] + fn verify_digest<D>(&self, msg_digest: D, sig: &Signature<C>) -> Result<()> + where + D: FixedOutput<OutputSize = FieldBytesSize<C>>, + { + self.verify_prehashed(&msg_digest.finalize_fixed(), sig) + } +} + +/// Bind a preferred [`Digest`] algorithm to an elliptic curve type. +/// +/// Generally there is a preferred variety of the SHA-2 family used with ECDSA +/// for a particular elliptic curve. +/// +/// This trait can be used to specify it, and with it receive a blanket impl of +/// [`PrehashSignature`], used by [`signature_derive`][1]) for the [`Signature`] +/// type for a particular elliptic curve. +/// +/// [1]: https://github.com/RustCrypto/traits/tree/master/signature/derive +#[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. + type Digest: BlockSizeUser + + Digest + + FixedOutput<OutputSize = FieldBytesSize<Self>> + + FixedOutputReset; +} + +#[cfg(feature = "digest")] +impl<C> PrehashSignature for Signature<C> +where + C: DigestPrimitive, + <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) +} + +/// Sign a prehashed message digest using the provided secret scalar and +/// ephemeral scalar, returning an ECDSA signature. +/// +/// Accepts the following arguments: +/// +/// - `d`: signing key. MUST BE UNIFORMLY RANDOM!!! +/// - `k`: ephemeral scalar value. MUST BE UNIFORMLY RANDOM!!! +/// - `z`: message digest to be signed. MUST BE OUTPUT OF A CRYPTOGRAPHICALLY +/// SECURE DIGEST ALGORITHM!!! +/// +/// # Returns +/// +/// ECDSA [`Signature`] and, when possible/desired, a [`RecoveryId`] +/// which can be used to recover the verifying key for a given signature. +#[cfg(feature = "arithmetic")] +#[allow(non_snake_case)] +pub fn sign_prehashed<C, K>( + d: &Scalar<C>, + k: K, + z: &FieldBytes<C>, +) -> Result<(Signature<C>, RecoveryId)> +where + C: PrimeCurve + CurveArithmetic, + K: AsRef<Scalar<C>> + Invert<Output = CtOption<Scalar<C>>>, + SignatureSize<C>: ArrayLength<u8>, +{ + // TODO(tarcieri): use `NonZeroScalar<C>` for `k`. + if k.as_ref().is_zero().into() { + return Err(Error::new()); + } + + let z = <Scalar<C> 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 = 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 = Scalar::<C>::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 * d)); + + // NOTE: `Signature::from_scalars` checks that both `r` and `s` are non-zero. + let signature = Signature::from_scalars(r, s)?; + let recovery_id = RecoveryId::new(R.y_is_odd().into(), x_is_reduced); + Ok((signature, recovery_id)) +} + +/// Verify the prehashed message against the provided ECDSA signature. +/// +/// Accepts the following arguments: +/// +/// - `q`: public key with which to verify the signature. +/// - `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. +#[cfg(feature = "arithmetic")] +pub fn verify_prehashed<C>( + q: &ProjectivePoint<C>, + z: &FieldBytes<C>, + sig: &Signature<C>, +) -> Result<()> +where + C: PrimeCurve + CurveArithmetic, + SignatureSize<C>: ArrayLength<u8>, +{ + let z = Scalar::<C>::reduce_bytes(z); + let (r, s) = sig.split_scalars(); + let s_inv = *s.invert_vartime(); + let u1 = z * s_inv; + let u2 = *r * s_inv; + let x = ProjectivePoint::<C>::lincomb(&ProjectivePoint::<C>::generator(), &u1, q, &u2) + .to_affine() + .x(); + + if *r == Scalar::<C>::reduce_bytes(&x) { + Ok(()) + } else { + Err(Error::new()) + } +} + +#[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 new file mode 100644 index 0000000..7825a96 --- /dev/null +++ b/vendor/ecdsa/src/lib.rs @@ -0,0 +1,708 @@ +#![no_std] +#![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", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::checked_conversions, + clippy::implicit_saturating_sub, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +//! ## `serde` support +//! +//! When the `serde` feature of this crate is enabled, `Serialize` and +//! `Deserialize` impls are provided for the [`Signature`] and [`VerifyingKey`] +//! types. +//! +//! Please see type-specific documentation for more information. +//! +//! ## Interop +//! +//! Any crates which provide an implementation of ECDSA for a particular +//! elliptic curve can leverage the types from this crate, along with the +//! [`k256`], [`p256`], and/or [`p384`] crates to expose ECDSA functionality in +//! a generic, interoperable way by leveraging the [`Signature`] type with in +//! conjunction with the [`signature::Signer`] and [`signature::Verifier`] +//! traits. +//! +//! For example, the [`ring-compat`] crate implements the [`signature::Signer`] +//! and [`signature::Verifier`] traits in conjunction with the +//! [`p256::ecdsa::Signature`] and [`p384::ecdsa::Signature`] types to +//! wrap the ECDSA implementations from [*ring*] in a generic, interoperable +//! API. +//! +//! [`k256`]: https://docs.rs/k256 +//! [`p256`]: https://docs.rs/p256 +//! [`p256::ecdsa::Signature`]: https://docs.rs/p256/latest/p256/ecdsa/type.Signature.html +//! [`p384`]: https://docs.rs/p384 +//! [`p384::ecdsa::Signature`]: https://docs.rs/p384/latest/p384/ecdsa/type.Signature.html +//! [`ring-compat`]: https://docs.rs/ring-compat +//! [*ring*]: https://docs.rs/ring + +#[cfg(feature = "alloc")] +extern crate alloc; + +mod recovery; + +#[cfg(feature = "der")] +pub mod der; +#[cfg(feature = "dev")] +pub mod dev; +#[cfg(feature = "hazmat")] +pub mod hazmat; +#[cfg(feature = "signing")] +mod signing; +#[cfg(feature = "verifying")] +mod verifying; + +pub use crate::recovery::RecoveryId; + +// Re-export the `elliptic-curve` crate (and select types) +pub use elliptic_curve::{self, sec1::EncodedPoint, PrimeCurve}; + +// Re-export the `signature` crate (and select types) +pub use signature::{self, Error, Result, SignatureEncoding}; + +#[cfg(feature = "signing")] +pub use crate::signing::SigningKey; +#[cfg(feature = "verifying")] +pub use crate::verifying::VerifyingKey; + +use core::{fmt, ops::Add}; +use elliptic_curve::{ + generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, + FieldBytes, FieldBytesSize, ScalarPrimitive, +}; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +#[cfg(feature = "arithmetic")] +use { + core::str, + 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> = <FieldBytesSize<C> as Add>::Output; + +/// Fixed-size byte array containing an ECDSA signature +pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>; + +/// ECDSA signature (fixed-size). Generic over elliptic curve types. +/// +/// Serialized as fixed-sized big endian scalar values with no added framing: +/// +/// - `r`: field element size for the given curve, big-endian +/// - `s`: field element size for the given curve, big-endian +/// +/// Both `r` and `s` MUST be non-zero. +/// +/// For example, in a curve with a 256-bit modulus like NIST P-256 or +/// secp256k1, `r` and `s` will both be 32-bytes and serialized as big endian, +/// resulting in a signature with a total of 64-bytes. +/// +/// ASN.1 DER-encoded signatures also supported via the +/// [`Signature::from_der`] and [`Signature::to_der`] methods. +/// +/// # `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 uses a hexadecimal encoding when used with +/// "human readable" text formats, and a binary encoding otherwise. +#[derive(Clone, Eq, PartialEq)] +pub struct Signature<C: PrimeCurve> { + r: ScalarPrimitive<C>, + s: ScalarPrimitive<C>, +} + +impl<C> Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + /// Parse a signature from fixed-width bytes, i.e. 2 * the size of + /// [`FieldBytes`] for a particular curve. + /// + /// # Returns + /// - `Ok(signature)` if the `r` and `s` components are both in the valid + /// range `1..n` when serialized as concatenated big endian integers. + /// - `Err(err)` if the `r` and/or `s` component of the signature is + /// out-of-range when interpreted as a big endian integer. + pub fn from_bytes(bytes: &SignatureBytes<C>) -> Result<Self> { + let (r_bytes, s_bytes) = bytes.split_at(C::FieldBytesSize::USIZE); + let r = FieldBytes::<C>::clone_from_slice(r_bytes); + let s = FieldBytes::<C>::clone_from_slice(s_bytes); + Self::from_scalars(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")] + pub fn from_der(bytes: &[u8]) -> Result<Self> + where + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, + { + der::Signature::<C>::try_from(bytes).and_then(Self::try_from) + } + + /// Create a [`Signature`] from the serialized `r` and `s` scalar values + /// which comprise the signature. + /// + /// # Returns + /// - `Ok(signature)` if the `r` and `s` components are both in the valid + /// range `1..n` when serialized as concatenated big endian integers. + /// - `Err(err)` if the `r` and/or `s` component of the signature is + /// out-of-range when interpreted as a big endian integer. + pub fn from_scalars(r: impl Into<FieldBytes<C>>, s: impl Into<FieldBytes<C>>) -> Result<Self> { + let r = ScalarPrimitive::from_slice(&r.into()).map_err(|_| Error::new())?; + let s = ScalarPrimitive::from_slice(&s.into()).map_err(|_| Error::new())?; + + if r.is_zero().into() || s.is_zero().into() { + return Err(Error::new()); + } + + Ok(Self { r, s }) + } + + /// Split the signature into its `r` and `s` components, represented as bytes. + pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) { + (self.r.to_bytes(), self.s.to_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. + #[cfg(feature = "der")] + pub fn to_der(&self) -> der::Signature<C> + where + der::MaxSize<C>: ArrayLength<u8>, + <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>, + { + 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")] + pub fn to_vec(&self) -> Vec<u8> { + self.to_bytes().to_vec() + } +} + +#[cfg(feature = "arithmetic")] +impl<C> Signature<C> +where + C: PrimeCurve + CurveArithmetic, + SignatureSize<C>: ArrayLength<u8>, +{ + /// Get the `r` component of this signature + pub fn r(&self) -> NonZeroScalar<C> { + NonZeroScalar::new(self.r.into()).unwrap() + } + + /// Get the `s` component of this signature + pub fn s(&self) -> NonZeroScalar<C> { + NonZeroScalar::new(self.s.into()).unwrap() + } + + /// Split the signature into its `r` and `s` scalars. + pub fn split_scalars(&self) -> (NonZeroScalar<C>, NonZeroScalar<C>) { + (self.r(), self.s()) + } + + /// Normalize signature into "low S" form as described in + /// [BIP 0062: Dealing with Malleability][1]. + /// + /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki + pub fn normalize_s(&self) -> Option<Self> { + let s = self.s(); + + if s.is_high().into() { + let mut result = self.clone(); + result.s = ScalarPrimitive::from(-s); + Some(result) + } else { + None + } + } +} + +impl<C> Copy for Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, + <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy, +{ +} + +impl<C> From<Signature<C>> for SignatureBytes<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + fn from(signature: Signature<C>) -> SignatureBytes<C> { + signature.to_bytes() + } +} + +impl<C> SignatureEncoding for Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + type Repr = SignatureBytes<C>; +} + +impl<C> TryFrom<&[u8]> for Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + type Error = Error; + + fn try_from(slice: &[u8]) -> Result<Self> { + Self::from_slice(slice) + } +} + +impl<C> fmt::Debug 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.to_bytes() { + write!(f, "{:02X}", byte)?; + } + + write!(f, ")") + } +} + +impl<C> fmt::Display for Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", self) + } +} + +impl<C> fmt::LowerHex for Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for byte in self.to_bytes() { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +} + +impl<C> fmt::UpperHex for Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for byte in self.to_bytes() { + write!(f, "{:02X}", byte)?; + } + Ok(()) + } +} + +#[cfg(feature = "arithmetic")] +impl<C> str::FromStr for Signature<C> +where + C: PrimeCurve + CurveArithmetic, + SignatureSize<C>: ArrayLength<u8>, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result<Self> { + if hex.as_bytes().len() != C::FieldBytesSize::USIZE * 4 { + return Err(Error::new()); + } + + // This check is mainly to ensure `hex.split_at` below won't panic + if !hex + .as_bytes() + .iter() + .all(|&byte| matches!(byte, b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z')) + { + return Err(Error::new()); + } + + let (r_hex, s_hex) = hex.split_at(C::FieldBytesSize::USIZE * 2); + + let r = r_hex + .parse::<NonZeroScalar<C>>() + .map_err(|_| Error::new())?; + + let s = s_hex + .parse::<NonZeroScalar<C>>() + .map_err(|_| Error::new())?; + + Self::from_scalars(r, s) + } +} + +/// 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")] +impl<C> Serialize for Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for Signature<C> +where + C: PrimeCurve, + SignatureSize<C>: ArrayLength<u8>, +{ + fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + let mut bytes = SignatureBytes::<C>::default(); + serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; + 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 new file mode 100644 index 0000000..dd1b6ae --- /dev/null +++ b/vendor/ecdsa/src/recovery.rs @@ -0,0 +1,357 @@ +//! Public key recovery support. + +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 +/// signature which is used during the recovery process to select the correct +/// public key from the signature. +/// +/// It consists of two bits of information: +/// +/// - low bit (0/1): was the y-coordinate of the affine point resulting from +/// the fixed-base multiplication 𝑘×𝑮 odd? This part of the algorithm +/// functions similar to point decompression. +/// - hi bit (3/4): did the affine x-coordinate of 𝑘×𝑮 overflow the order of +/// the scalar field, requiring a reduction when computing `r`? +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct RecoveryId(u8); + +impl RecoveryId { + /// Maximum supported value for the recovery ID (inclusive). + pub const MAX: u8 = 3; + + /// Create a new [`RecoveryId`] from the following 1-bit arguments: + /// + /// - `is_y_odd`: is the affine y-coordinate of 𝑘×𝑮 odd? + /// - `is_x_reduced`: did the affine x-coordinate of 𝑘×𝑮 overflow the curve order? + pub const fn new(is_y_odd: bool, is_x_reduced: bool) -> Self { + Self((is_x_reduced as u8) << 1 | (is_y_odd as u8)) + } + + /// Did the affine x-coordinate of 𝑘×𝑮 overflow the curve order? + pub const fn is_x_reduced(self) -> bool { + (self.0 & 0b10) != 0 + } + + /// Is the affine y-coordinate of 𝑘×𝑮 odd? + pub const fn is_y_odd(self) -> bool { + (self.0 & 1) != 0 + } + + /// Convert a `u8` into a [`RecoveryId`]. + pub const fn from_byte(byte: u8) -> Option<Self> { + if byte <= Self::MAX { + Some(Self(byte)) + } else { + None + } + } + + /// Convert this [`RecoveryId`] into a `u8`. + pub const fn to_byte(self) -> u8 { + self.0 + } +} + +#[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; + + fn try_from(byte: u8) -> Result<Self> { + Self::from_byte(byte).ok_or_else(Error::new) + } +} + +impl From<RecoveryId> for u8 { + fn from(id: RecoveryId) -> u8 { + id.0 + } +} + +#[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; + + #[test] + fn new() { + assert_eq!(RecoveryId::new(false, false).to_byte(), 0); + assert_eq!(RecoveryId::new(true, false).to_byte(), 1); + assert_eq!(RecoveryId::new(false, true).to_byte(), 2); + assert_eq!(RecoveryId::new(true, true).to_byte(), 3); + } + + #[test] + fn try_from() { + for n in 0u8..=3 { + assert_eq!(RecoveryId::try_from(n).unwrap().to_byte(), n); + } + + for n in 4u8..=255 { + assert!(RecoveryId::try_from(n).is_err()); + } + } + + #[test] + fn is_x_reduced() { + assert_eq!(RecoveryId::try_from(0).unwrap().is_x_reduced(), false); + assert_eq!(RecoveryId::try_from(1).unwrap().is_x_reduced(), false); + assert_eq!(RecoveryId::try_from(2).unwrap().is_x_reduced(), true); + assert_eq!(RecoveryId::try_from(3).unwrap().is_x_reduced(), true); + } + + #[test] + fn is_y_odd() { + assert_eq!(RecoveryId::try_from(0).unwrap().is_y_odd(), false); + assert_eq!(RecoveryId::try_from(1).unwrap().is_y_odd(), true); + assert_eq!(RecoveryId::try_from(2).unwrap().is_y_odd(), false); + assert_eq!(RecoveryId::try_from(3).unwrap().is_y_odd(), true); + } +} diff --git a/vendor/ecdsa/src/signing.rs b/vendor/ecdsa/src/signing.rs new file mode 100644 index 0000000..3a40c6d --- /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/verifying.rs b/vendor/ecdsa/src/verifying.rs new file mode 100644 index 0000000..4ac0570 --- /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) + } +} diff --git a/vendor/ecdsa/tests/lib.rs b/vendor/ecdsa/tests/lib.rs new file mode 100644 index 0000000..1b622f8 --- /dev/null +++ b/vendor/ecdsa/tests/lib.rs @@ -0,0 +1,14 @@ +//! Smoke tests which use `MockCurve` + +#![cfg(feature = "dev")] + +use elliptic_curve::dev::MockCurve; + +type Signature = ecdsa::Signature<MockCurve>; +type SignatureBytes = ecdsa::SignatureBytes<MockCurve>; + +#[test] +fn rejects_all_zero_signature() { + let all_zero_bytes = SignatureBytes::default(); + assert!(Signature::try_from(all_zero_bytes.as_ref()).is_err()); +} |