From cf81fb325c97ed6a748907cd7b9059790553eaff Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Thu, 5 Sep 2024 15:00:43 -0700 Subject: [PATCH] ecdsa,dsa,ed25519,ed448: pkcs8 API changes (#851) Signed-off-by: Arthur Gautier --- Cargo.lock | 17 +++++++---------- Cargo.toml | 6 ++++++ dsa/src/signing_key.rs | 18 +++++++++++------- ecdsa/Cargo.toml | 2 +- ecdsa/src/der.rs | 6 +++--- ecdsa/src/signing.rs | 4 ++-- ed25519/src/pkcs8.rs | 24 ++++++++++++++++-------- ed448/src/pkcs8.rs | 24 ++++++++++++++++-------- 8 files changed, 62 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d99f7f00..31a8e49c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,9 +319,9 @@ dependencies = [ [[package]] name = "der" -version = "0.8.0-rc.0" +version = "0.8.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d9c07d3bd80cf0935ce478d07edf7e7a5b158446757f988f3e62082227b700" +checksum = "82db698b33305f0134faf590b9d1259dc171b5481ac41d5c8146c3b3ee7d4319" dependencies = [ "const-oid", "pem-rfc7468", @@ -419,8 +419,7 @@ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "elliptic-curve" version = "0.14.0-pre.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed8e96bb573517f42470775f8ef1b9cd7595de52ba7a8e19c48325a92c8fe4f" +source = "git+https://github.com/baloo/traits.git?branch=baloo/elliptic-curve/pkcs8-API-break#1b036fe61696772d74f5195db9f9338936795929" dependencies = [ "base16ct", "crypto-bigint", @@ -767,9 +766,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pem-rfc7468" -version = "1.0.0-rc.0" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b24c1c4a3b352d47de5ec824193e68317dc0ce041f6279a4771eb550ab7f8c" +checksum = "b6c1cde4770761bf6bd336f947b9ac1fe700b0a4ec5867cf66cf08597fe89e8c" dependencies = [ "base64ct", ] @@ -777,8 +776,7 @@ dependencies = [ [[package]] name = "pkcs8" version = "0.11.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66180445f1dce533620a7743467ef85fe1c5e80cdaf7c7053609d7a2fbcdae20" +source = "git+https://github.com/RustCrypto/formats.git#3fb883b2f445e74f38f51fef63a347ecfe69f623" dependencies = [ "der", "spki", @@ -1034,8 +1032,7 @@ dependencies = [ [[package]] name = "sec1" version = "0.8.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c98827dc6ed0ea1707286a3d14b4ad4e25e2643169cbf111568a46ff5b09f5" +source = "git+https://github.com/RustCrypto/formats.git#3fb883b2f445e74f38f51fef63a347ecfe69f623" dependencies = [ "base16ct", "der", diff --git a/Cargo.toml b/Cargo.toml index d9709ecd..59ed081c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,9 @@ members = [ [profile.dev] opt-level = 2 + +[patch.crates-io] +sec1 = { git = "https://github.com/RustCrypto/formats.git" } +pkcs8 = { git = "https://github.com/RustCrypto/formats.git" } +# https://github.com/RustCrypto/traits/pull/1650 +elliptic-curve = { git = "https://github.com/baloo/traits.git", branch = "baloo/elliptic-curve/pkcs8-API-break" } diff --git a/dsa/src/signing_key.rs b/dsa/src/signing_key.rs index 698f0576..bcd7e029 100644 --- a/dsa/src/signing_key.rs +++ b/dsa/src/signing_key.rs @@ -11,8 +11,11 @@ use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset}; use num_bigint::BigUint; use num_traits::Zero; use pkcs8::{ - der::{asn1::UintRef, AnyRef, Decode, Encode}, - AlgorithmIdentifierRef, EncodePrivateKey, PrivateKeyInfo, SecretDocument, + der::{ + asn1::{OctetStringRef, UintRef}, + AnyRef, Decode, Encode, + }, + AlgorithmIdentifierRef, EncodePrivateKey, PrivateKeyInfoRef, SecretDocument, }; use signature::{ hazmat::{PrehashSigner, RandomizedPrehashSigner}, @@ -182,7 +185,8 @@ impl EncodePrivateKey for SigningKey { let x = UintRef::new(&x_bytes)?; let mut signing_key = x.to_der()?; - let signing_key_info = PrivateKeyInfo::new(algorithm, &signing_key); + let signing_key_info = + PrivateKeyInfoRef::new(algorithm, OctetStringRef::new(&signing_key)?); let secret_document = signing_key_info.try_into()?; signing_key.zeroize(); @@ -192,19 +196,19 @@ impl EncodePrivateKey for SigningKey { } } -impl<'a> TryFrom> for SigningKey { +impl<'a> TryFrom> for SigningKey { type Error = pkcs8::Error; - fn try_from(value: PrivateKeyInfo<'a>) -> Result { + fn try_from(value: PrivateKeyInfoRef<'a>) -> Result { value.algorithm.assert_algorithm_oid(OID)?; let parameters = value.algorithm.parameters_any()?; let components = parameters.decode_as::()?; - let x = UintRef::from_der(value.private_key)?; + let x = UintRef::from_der(value.private_key.as_bytes())?; let x = BigUint::from_bytes_be(x.as_bytes()); - let y = if let Some(y_bytes) = value.public_key { + let y = if let Some(y_bytes) = value.public_key.as_ref().and_then(|bs| bs.as_bytes()) { let y = UintRef::from_der(y_bytes)?; BigUint::from_bytes_be(y.as_bytes()) } else { diff --git a/ecdsa/Cargo.toml b/ecdsa/Cargo.toml index 2cd66612..54a160d2 100644 --- a/ecdsa/Cargo.toml +++ b/ecdsa/Cargo.toml @@ -21,7 +21,7 @@ elliptic-curve = { version = "=0.14.0-pre.6", default-features = false, features signature = { version = "=2.3.0-pre.4", default-features = false, features = ["rand_core"] } # optional dependencies -der = { version = "0.8.0-rc.0", optional = true } +der = { version = "0.8.0-rc.1", optional = true } digest = { version = "=0.11.0-pre.9", optional = true, default-features = false, features = ["oid"] } rfc6979 = { version = "=0.5.0-pre.4", optional = true, path = "../rfc6979" } serdect = { version = "0.2", optional = true, default-features = false, features = ["alloc"] } diff --git a/ecdsa/src/der.rs b/ecdsa/src/der.rs index 22d6edbd..7d7e4e3a 100644 --- a/ecdsa/src/der.rs +++ b/ecdsa/src/der.rs @@ -8,7 +8,7 @@ use core::{ fmt::{self, Debug}, ops::{Add, Range}, }; -use der::{asn1::UintRef, Decode, Encode, FixedTag, Length, Reader, Tag, Writer}; +use der::{asn1::UintRef, Decode, Encode, FixedTag, Header, Length, Reader, Tag, Writer}; use elliptic_curve::{ array::{typenum::Unsigned, Array, ArraySize}, consts::U9, @@ -206,7 +206,7 @@ where type Error = der::Error; fn decode>(reader: &mut R) -> der::Result { - let header = reader.peek_header()?; + let header = Header::peek(reader)?; header.tag.assert_eq(Tag::Sequence)?; let mut buf = SignatureBytes::::default(); @@ -359,7 +359,7 @@ where /// 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)?; + let header = Header::decode(&mut reader)?; header.tag.assert_eq(Tag::Sequence)?; let ret = reader.read_nested::<_, _, der::Error>(header.length, |reader| { diff --git a/ecdsa/src/signing.rs b/ecdsa/src/signing.rs index 7be7dee6..513580de 100644 --- a/ecdsa/src/signing.rs +++ b/ecdsa/src/signing.rs @@ -545,7 +545,7 @@ where } #[cfg(feature = "pkcs8")] -impl TryFrom> for SigningKey +impl TryFrom> for SigningKey where C: EcdsaCurve + AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, @@ -555,7 +555,7 @@ where { type Error = pkcs8::Error; - fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + fn try_from(private_key_info: pkcs8::PrivateKeyInfoRef<'_>) -> pkcs8::Result { SecretKey::try_from(private_key_info).map(Into::into) } } diff --git a/ed25519/src/pkcs8.rs b/ed25519/src/pkcs8.rs index 92039aec..cac2f9b2 100644 --- a/ed25519/src/pkcs8.rs +++ b/ed25519/src/pkcs8.rs @@ -15,14 +15,17 @@ //! breaking changes when using this module. pub use pkcs8::{ - spki, DecodePrivateKey, DecodePublicKey, Error, ObjectIdentifier, PrivateKeyInfo, Result, + spki, DecodePrivateKey, DecodePublicKey, Error, ObjectIdentifier, PrivateKeyInfoRef, Result, }; #[cfg(feature = "alloc")] pub use pkcs8::{spki::EncodePublicKey, EncodePrivateKey}; #[cfg(feature = "alloc")] -pub use pkcs8::der::{asn1::BitStringRef, Document, SecretDocument}; +pub use pkcs8::der::{ + asn1::{BitStringRef, OctetStringRef}, + Document, SecretDocument, +}; use core::fmt; @@ -128,10 +131,14 @@ impl EncodePrivateKey for KeypairBytes { private_key[1] = 0x20; private_key[2..].copy_from_slice(&self.secret_key); - let private_key_info = PrivateKeyInfo { + let private_key_info = PrivateKeyInfoRef { algorithm: ALGORITHM_ID, - private_key: &private_key, - public_key: self.public_key.as_ref().map(|pk| pk.0.as_slice()), + private_key: OctetStringRef::new(&private_key)?, + public_key: self + .public_key + .as_ref() + .map(|pk| BitStringRef::new(0, &pk.0)) + .transpose()?, }; let result = SecretDocument::encode_msg(&private_key_info)?; @@ -143,10 +150,10 @@ impl EncodePrivateKey for KeypairBytes { } } -impl TryFrom> for KeypairBytes { +impl TryFrom> for KeypairBytes { type Error = Error; - fn try_from(private_key: PrivateKeyInfo<'_>) -> Result { + fn try_from(private_key: PrivateKeyInfoRef<'_>) -> Result { private_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; if private_key.algorithm.parameters.is_some() { @@ -161,13 +168,14 @@ impl TryFrom> for KeypairBytes { // // - 0x04: OCTET STRING tag // - 0x20: 32-byte length - let secret_key = match private_key.private_key { + let secret_key = match private_key.private_key.as_bytes() { [0x04, 0x20, rest @ ..] => rest.try_into().map_err(|_| Error::KeyMalformed), _ => Err(Error::KeyMalformed), }?; let public_key = private_key .public_key + .and_then(|bs| bs.as_bytes()) .map(|bytes| bytes.try_into().map_err(|_| Error::KeyMalformed)) .transpose()? .map(PublicKeyBytes); diff --git a/ed448/src/pkcs8.rs b/ed448/src/pkcs8.rs index bdc833a2..a12eda85 100644 --- a/ed448/src/pkcs8.rs +++ b/ed448/src/pkcs8.rs @@ -15,14 +15,17 @@ //! breaking changes when using this module. pub use pkcs8::{ - spki, DecodePrivateKey, DecodePublicKey, Error, ObjectIdentifier, PrivateKeyInfo, Result, + spki, DecodePrivateKey, DecodePublicKey, Error, ObjectIdentifier, PrivateKeyInfoRef, Result, }; #[cfg(feature = "alloc")] pub use pkcs8::{spki::EncodePublicKey, EncodePrivateKey}; #[cfg(feature = "alloc")] -pub use pkcs8::der::{asn1::BitStringRef, Document, SecretDocument}; +pub use pkcs8::der::{ + asn1::{BitStringRef, OctetStringRef}, + Document, SecretDocument, +}; #[cfg(feature = "zeroize")] use zeroize::Zeroize; @@ -122,10 +125,14 @@ impl EncodePrivateKey for KeypairBytes { private_key[1] = 0x39; private_key[2..].copy_from_slice(&self.secret_key); - let private_key_info = PrivateKeyInfo { + let private_key_info = PrivateKeyInfoRef { algorithm: ALGORITHM_ID, - private_key: &private_key, - public_key: self.public_key.as_ref().map(|pk| pk.0.as_slice()), + private_key: OctetStringRef::new(&private_key)?, + public_key: self + .public_key + .as_ref() + .map(|pk| BitStringRef::new(0, &pk.0)) + .transpose()?, }; let result = SecretDocument::encode_msg(&private_key_info)?; @@ -136,10 +143,10 @@ impl EncodePrivateKey for KeypairBytes { } } -impl TryFrom> for KeypairBytes { +impl TryFrom> for KeypairBytes { type Error = Error; - fn try_from(private_key: PrivateKeyInfo<'_>) -> Result { + fn try_from(private_key: PrivateKeyInfoRef<'_>) -> Result { private_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; if private_key.algorithm.parameters.is_some() { @@ -154,13 +161,14 @@ impl TryFrom> for KeypairBytes { // // - 0x04: OCTET STRING tag // - 0x39: 57-byte length - let secret_key = match private_key.private_key { + let secret_key = match private_key.private_key.as_bytes() { [0x04, 0x39, rest @ ..] => rest.try_into().map_err(|_| Error::KeyMalformed), _ => Err(Error::KeyMalformed), }?; let public_key = private_key .public_key + .and_then(|bs| bs.as_bytes()) .map(|bytes| bytes.try_into().map_err(|_| Error::KeyMalformed)) .transpose()? .map(PublicKeyBytes);