From 53ecc95940fea10fb654a13edbe61764a59ca8a7 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 4 Aug 2023 04:24:58 +0000 Subject: [PATCH 01/14] pkcs8: provide `PrivateKeyInfoRef`/`PrivateKeyInfoOwned` Signed-off-by: Arthur Gautier --- pkcs8/src/lib.rs | 4 +- pkcs8/src/private_key_info.rs | 154 ++++++++++++++++++++++----- pkcs8/src/traits.rs | 14 +-- pkcs8/tests/encrypted_private_key.rs | 6 +- pkcs8/tests/private_key.rs | 45 ++++---- pkcs8/tests/traits.rs | 8 +- 6 files changed, 165 insertions(+), 66 deletions(-) diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index 33ceef8e2..6578e3a18 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -85,7 +85,7 @@ pub(crate) mod encrypted_private_key_info; pub use crate::{ error::{Error, Result}, - private_key_info::PrivateKeyInfo, + private_key_info::{PrivateKeyInfo, PrivateKeyInfoRef}, traits::DecodePrivateKey, version::Version, }; @@ -96,7 +96,7 @@ pub use spki::{ #[cfg(feature = "alloc")] pub use { - crate::traits::EncodePrivateKey, + crate::{private_key_info::PrivateKeyInfoOwned, traits::EncodePrivateKey}, der::{Document, SecretDocument}, spki::EncodePublicKey, }; diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index 03b7ca162..89146450d 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -1,15 +1,19 @@ //! PKCS#8 `PrivateKeyInfo`. -use crate::{AlgorithmIdentifierRef, Error, Result, Version}; +use crate::{Error, Result, Version}; use core::fmt; use der::{ asn1::{AnyRef, BitStringRef, ContextSpecific, OctetStringRef}, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, TagMode, TagNumber, Writer, }; +use spki::AlgorithmIdentifier; #[cfg(feature = "alloc")] -use der::SecretDocument; +use { + alloc::boxed::Box, + der::{asn1::Any, SecretDocument}, +}; #[cfg(feature = "encryption")] use { @@ -87,23 +91,23 @@ const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1; /// [RFC 5208 Section 5]: https://tools.ietf.org/html/rfc5208#section-5 /// [RFC 5958 Section 2]: https://datatracker.ietf.org/doc/html/rfc5958#section-2 #[derive(Clone)] -pub struct PrivateKeyInfo<'a> { +pub struct PrivateKeyInfo { /// X.509 `AlgorithmIdentifier` for the private key type. - pub algorithm: AlgorithmIdentifierRef<'a>, + pub algorithm: AlgorithmIdentifier, /// Private key data. - pub private_key: &'a [u8], + pub private_key: Key, /// Public key data, optionally available if version is V2. - pub public_key: Option<&'a [u8]>, + pub public_key: Option, } -impl<'a> PrivateKeyInfo<'a> { +impl PrivateKeyInfo { /// Create a new PKCS#8 [`PrivateKeyInfo`] message. /// /// This is a helper method which initializes `attributes` and `public_key` /// to `None`, helpful if you aren't using those. - pub fn new(algorithm: AlgorithmIdentifierRef<'a>, private_key: &'a [u8]) -> Self { + pub fn new(algorithm: AlgorithmIdentifier, private_key: Key) -> Self { Self { algorithm, private_key, @@ -121,7 +125,12 @@ impl<'a> PrivateKeyInfo<'a> { Version::V1 } } - +} +impl<'a, Params, Key> PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: From<&'a [u8]> + AsRef<[u8]>, +{ /// Encrypt this private key using a symmetric encryption key derived /// from the provided password. /// @@ -152,12 +161,19 @@ impl<'a> PrivateKeyInfo<'a> { let der = Zeroizing::new(self.to_der()?); EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, der.as_ref()) } +} +impl<'a, Params, Key> PrivateKeyInfo +where + Params: der::Choice<'a> + Encode, + Key: AsRef<[u8]>, +{ /// Get a `BIT STRING` representation of the public key, if present. - fn public_key_bit_string(&self) -> der::Result>>> { + fn public_key_bit_string(&self) -> der::Result>>> { self.public_key + .as_ref() .map(|pk| { - BitStringRef::from_bytes(pk).map(|value| ContextSpecific { + BitStringRef::from_bytes(pk.as_ref()).map(|value| ContextSpecific { tag_number: PUBLIC_KEY_TAG, tag_mode: TagMode::Implicit, value, @@ -167,23 +183,29 @@ impl<'a> PrivateKeyInfo<'a> { } } -impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { +impl<'a, Params, Key> DecodeValue<'a> for PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: From<&'a [u8]>, +{ type Error = der::Error; fn decode_value>( reader: &mut R, header: Header, - ) -> der::Result> { + ) -> der::Result> { reader.read_nested(header.length, |reader| { // Parse and validate `version` INTEGER. let version = Version::decode(reader)?; let algorithm = reader.decode()?; - let private_key = OctetStringRef::decode(reader)?.into(); + let private_key: &[u8] = OctetStringRef::decode(reader)?.into(); + let private_key = Key::try_from(private_key)?; let public_key = reader .context_specific::>(PUBLIC_KEY_TAG, TagMode::Implicit)? .map(|bs| { bs.as_bytes() .ok_or_else(|| der::Tag::BitString.value_error()) + .map(Key::from) }) .transpose()?; @@ -212,26 +234,39 @@ impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { } } -impl EncodeValue for PrivateKeyInfo<'_> { +impl<'a, Params, Key> EncodeValue for PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: AsRef<[u8]>, +{ fn value_len(&self) -> der::Result { self.version().encoded_len()? + self.algorithm.encoded_len()? - + OctetStringRef::new(self.private_key)?.encoded_len()? + + OctetStringRef::new(self.private_key.as_ref())?.encoded_len()? + self.public_key_bit_string()?.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.version().encode(writer)?; self.algorithm.encode(writer)?; - OctetStringRef::new(self.private_key)?.encode(writer)?; + OctetStringRef::new(self.private_key.as_ref())?.encode(writer)?; self.public_key_bit_string()?.encode(writer)?; Ok(()) } } -impl<'a> Sequence<'a> for PrivateKeyInfo<'a> {} +impl<'a, Params, Key> Sequence<'a> for PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: From<&'a [u8]> + AsRef<[u8]>, +{ +} -impl<'a> TryFrom<&'a [u8]> for PrivateKeyInfo<'a> { +impl<'a, Params, Key> TryFrom<&'a [u8]> for PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: From<&'a [u8]> + AsRef<[u8]> + 'a, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -239,7 +274,11 @@ impl<'a> TryFrom<&'a [u8]> for PrivateKeyInfo<'a> { } } -impl<'a> fmt::Debug for PrivateKeyInfo<'a> { +impl fmt::Debug for PrivateKeyInfo +where + Params: fmt::Debug, + Key: fmt::Debug, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PrivateKeyInfo") .field("version", &self.version()) @@ -250,45 +289,102 @@ impl<'a> fmt::Debug for PrivateKeyInfo<'a> { } #[cfg(feature = "alloc")] -impl TryFrom> for SecretDocument { +impl<'a, Params, Key> TryFrom> for SecretDocument +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: From<&'a [u8]> + AsRef<[u8]>, +{ type Error = Error; - fn try_from(private_key: PrivateKeyInfo<'_>) -> Result { + fn try_from(private_key: PrivateKeyInfo) -> Result { SecretDocument::try_from(&private_key) } } #[cfg(feature = "alloc")] -impl TryFrom<&PrivateKeyInfo<'_>> for SecretDocument { +impl<'a, Params, Key> TryFrom<&PrivateKeyInfo> for SecretDocument +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: From<&'a [u8]> + AsRef<[u8]>, +{ type Error = Error; - fn try_from(private_key: &PrivateKeyInfo<'_>) -> Result { + fn try_from(private_key: &PrivateKeyInfo) -> Result { Ok(Self::encode_msg(private_key)?) } } #[cfg(feature = "pem")] -impl PemLabel for PrivateKeyInfo<'_> { +impl PemLabel for PrivateKeyInfo { const PEM_LABEL: &'static str = "PRIVATE KEY"; } #[cfg(feature = "subtle")] -impl<'a> ConstantTimeEq for PrivateKeyInfo<'a> { +impl ConstantTimeEq for PrivateKeyInfo +where + Params: Eq, + Key: PartialEq + AsRef<[u8]>, +{ fn ct_eq(&self, other: &Self) -> Choice { // NOTE: public fields are not compared in constant time let public_fields_eq = self.algorithm == other.algorithm && self.public_key == other.public_key; - self.private_key.ct_eq(other.private_key) & Choice::from(public_fields_eq as u8) + self.private_key.as_ref().ct_eq(other.private_key.as_ref()) + & Choice::from(public_fields_eq as u8) } } #[cfg(feature = "subtle")] -impl<'a> Eq for PrivateKeyInfo<'a> {} +impl Eq for PrivateKeyInfo +where + Params: Eq, + Key: AsRef<[u8]> + Eq, +{ +} #[cfg(feature = "subtle")] -impl<'a> PartialEq for PrivateKeyInfo<'a> { +impl PartialEq for PrivateKeyInfo +where + Params: Eq, + Key: PartialEq + AsRef<[u8]>, +{ fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } + +/// [`PrivateKeyInfo`] with [`AnyRef`] algorithm parameters, and `&[u8]` key. +pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, &'a [u8]>; + +/// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and `Box<[u8]>` key. +#[cfg(feature = "alloc")] +pub type PrivateKeyInfoOwned = PrivateKeyInfo>; + +#[cfg(feature = "alloc")] +mod allocating { + use super::*; + use der::referenced::*; + + impl<'a> RefToOwned<'a> for PrivateKeyInfoRef<'a> { + type Owned = PrivateKeyInfoOwned; + fn ref_to_owned(&self) -> Self::Owned { + PrivateKeyInfoOwned { + algorithm: self.algorithm.ref_to_owned(), + private_key: self.private_key.ref_to_owned(), + public_key: self.public_key.ref_to_owned(), + } + } + } + + impl OwnedToRef for PrivateKeyInfoOwned { + type Borrowed<'a> = PrivateKeyInfoRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + PrivateKeyInfoRef { + algorithm: self.algorithm.owned_to_ref(), + private_key: self.private_key.owned_to_ref(), + public_key: self.public_key.owned_to_ref(), + } + } + } +} diff --git a/pkcs8/src/traits.rs b/pkcs8/src/traits.rs index a38a78e6d..07b0ac832 100644 --- a/pkcs8/src/traits.rs +++ b/pkcs8/src/traits.rs @@ -1,6 +1,6 @@ //! Traits for parsing objects from PKCS#8 encoded documents -use crate::{Error, PrivateKeyInfo, Result}; +use crate::{Error, PrivateKeyInfoRef, Result}; #[cfg(feature = "alloc")] use der::SecretDocument; @@ -46,7 +46,7 @@ pub trait DecodePrivateKey: Sized { fn from_pkcs8_pem(s: &str) -> Result { // Validate PEM label let label = pem::decode_label(s.as_bytes())?; - PrivateKeyInfo::validate_pem_label(label)?; + PrivateKeyInfoRef::validate_pem_label(label)?; let doc = SecretDocument::from_pem(s)?.1; Self::from_pkcs8_der(doc.as_bytes()) @@ -78,17 +78,17 @@ pub trait DecodePrivateKey: Sized { #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs8_pem_file(path: impl AsRef) -> Result { let (label, doc) = SecretDocument::read_pem_file(path)?; - PrivateKeyInfo::validate_pem_label(&label)?; + PrivateKeyInfoRef::validate_pem_label(&label)?; Self::from_pkcs8_der(doc.as_bytes()) } } impl DecodePrivateKey for T where - T: for<'a> TryFrom, Error = Error>, + T: for<'a> TryFrom, Error = Error>, { fn from_pkcs8_der(bytes: &[u8]) -> Result { - Self::try_from(PrivateKeyInfo::try_from(bytes)?) + Self::try_from(PrivateKeyInfoRef::try_from(bytes)?) } } @@ -113,7 +113,7 @@ pub trait EncodePrivateKey { #[cfg(feature = "pem")] fn to_pkcs8_pem(&self, line_ending: LineEnding) -> Result> { let doc = self.to_pkcs8_der()?; - Ok(doc.to_pem(PrivateKeyInfo::PEM_LABEL, line_ending)?) + Ok(doc.to_pem(PrivateKeyInfoRef::PEM_LABEL, line_ending)?) } /// Serialize this private key as an encrypted PEM-encoded PKCS#8 private @@ -139,6 +139,6 @@ pub trait EncodePrivateKey { #[cfg(all(feature = "pem", feature = "std"))] fn write_pkcs8_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs8_der()?; - Ok(doc.write_pem_file(path, PrivateKeyInfo::PEM_LABEL, line_ending)?) + Ok(doc.write_pem_file(path, PrivateKeyInfoRef::PEM_LABEL, line_ending)?) } } diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index cd7ad6b0a..716ba97da 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -3,7 +3,7 @@ #![cfg(feature = "pkcs5")] use hex_literal::hex; -use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo, PrivateKeyInfo}; +use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo, PrivateKeyInfoRef}; #[cfg(feature = "alloc")] use der::Encode; @@ -248,7 +248,7 @@ fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(pbes2_params, PASSWORD) .unwrap(); @@ -269,7 +269,7 @@ fn encrypt_ed25519_der_encpriv_aes256_scrypt() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(scrypt_params, PASSWORD) .unwrap(); diff --git a/pkcs8/tests/private_key.rs b/pkcs8/tests/private_key.rs index d1dce2b54..5572cd722 100644 --- a/pkcs8/tests/private_key.rs +++ b/pkcs8/tests/private_key.rs @@ -2,7 +2,7 @@ use der::asn1::ObjectIdentifier; use hex_literal::hex; -use pkcs8::{PrivateKeyInfo, Version}; +use pkcs8::{PrivateKeyInfoRef, Version}; #[cfg(feature = "alloc")] use der::Encode; @@ -49,7 +49,7 @@ const X25519_PEM_EXAMPLE: &str = include_str!("examples/x25519-priv.pem"); #[test] fn decode_ec_p256_der() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.2.840.10045.2.1".parse().unwrap()); @@ -65,7 +65,7 @@ fn decode_ec_p256_der() { // Extracted with: // $ openssl asn1parse -inform der -in tests/examples/p256-priv.der - assert_eq!(pk.private_key, &hex!("306B020101042069624171561A63340DE0E7D869F2A05492558E1A04868B6A9F854A866788188DA144034200041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F")[..]); + assert_eq!(pk.private_key.as_ref(), &hex!("306B020101042069624171561A63340DE0E7D869F2A05492558E1A04868B6A9F854A866788188DA144034200041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F")[..]); } #[test] @@ -98,7 +98,7 @@ fn decode_ec_bignp256_der() { // https://datatracker.ietf.org/doc/html/rfc8410#section-10.3 #[test] fn decode_ed25519_der_v1() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -106,7 +106,7 @@ fn decode_ed25519_der_v1() { // Extracted with: // $ openssl asn1parse -inform der -in tests/examples/ed25519-priv.der assert_eq!( - pk.private_key, + pk.private_key.as_ref(), &hex!("042017ED9C73E9DB649EC189A612831C5FC570238207C1AA9DFBD2C53E3FF5E5EA85")[..] ); } @@ -122,29 +122,32 @@ fn decode_ed25519_der_v2() { const PUB_KEY: [u8; 32] = hex!("19BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1"); - let pk = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V2); assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); - assert_eq!(pk.private_key, PRIV_KEY); - assert_eq!(pk.public_key, Some(&PUB_KEY[..])); + assert_eq!(pk.private_key.as_ref(), PRIV_KEY); + assert_eq!( + pk.public_key.as_ref().map(|p| p.as_ref()), + Some(&PUB_KEY[..]) + ); } #[test] fn decode_rsa_2048_der() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.2.840.113549.1.1.1".parse().unwrap()); assert!(pk.algorithm.parameters.unwrap().is_null()); // Extracted with: // $ openssl asn1parse -inform der -in tests/examples/rsa2048-priv.der - assert_eq!(pk.private_key, &hex!("308204A30201000282010100B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F0203010001028201007ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C102818100DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D6702818100D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F902818100CE68B7AC1B0D100D636E55488753C5C09843FDB390E2705DF7689457C9BD8D9765E30978617E2EFC8048F4C324206DB86087B654E97BB3D464E7EE3F8CD83FE10436F7DF18E9A963C4E64911D67EDE34042F2E26E3D3A1AD346ADAD6B9B7F67708CB094E62DEE9FF4D5D6669AF988AF2255D1CE8ED317C6A7D8691DA354D12DB02818025F6E5944220286B4DFBBF4235C0EE5843D2198091895120D6CA7B200B826D3ECE738E2E00498FAC0A2A6CA969C7F0C3CA1AB0BC40297132BE7538D7BEDF4CB0EFC6B98EF7DBA54F56AA99AABCE534C49C27947D4678C51C63C78C7CE1687231B4C8EB587AE6EF0480CBAF4FC0173CFD587A7E67AF515FB9B9DE75111839722902818031995406D406207CADEAEA35B38D040C5F8A9A1AE0827E9ED06B153D83B6821935B4B36A82BE9D56C791B58C27271A5793D53A1D657C08997960B1433E5171987F452F144A7C72306D63E1D3FFC0B71B75AB08F2E45A482E988451CBE478E12EB228D07456C924B66F6CED048D853F533E31A68614F1C3CE6D8EC9983CE72AF7")[..]); + assert_eq!(pk.private_key.as_ref(), &hex!("308204A30201000282010100B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F0203010001028201007ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C102818100DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D6702818100D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F902818100CE68B7AC1B0D100D636E55488753C5C09843FDB390E2705DF7689457C9BD8D9765E30978617E2EFC8048F4C324206DB86087B654E97BB3D464E7EE3F8CD83FE10436F7DF18E9A963C4E64911D67EDE34042F2E26E3D3A1AD346ADAD6B9B7F67708CB094E62DEE9FF4D5D6669AF988AF2255D1CE8ED317C6A7D8691DA354D12DB02818025F6E5944220286B4DFBBF4235C0EE5843D2198091895120D6CA7B200B826D3ECE738E2E00498FAC0A2A6CA969C7F0C3CA1AB0BC40297132BE7538D7BEDF4CB0EFC6B98EF7DBA54F56AA99AABCE534C49C27947D4678C51C63C78C7CE1687231B4C8EB587AE6EF0480CBAF4FC0173CFD587A7E67AF515FB9B9DE75111839722902818031995406D406207CADEAEA35B38D040C5F8A9A1AE0827E9ED06B153D83B6821935B4B36A82BE9D56C791B58C27271A5793D53A1D657C08997960B1433E5171987F452F144A7C72306D63E1D3FFC0B71B75AB08F2E45A482E988451CBE478E12EB228D07456C924B66F6CED048D853F533E31A68614F1C3CE6D8EC9983CE72AF7")[..]); } #[test] fn decode_x25519_der() { - let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(X25519_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.3.101.110".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -152,7 +155,7 @@ fn decode_x25519_der() { // Extracted with: // $ openssl asn1parse -inform der -in tests/examples/x25519-priv.der assert_eq!( - pk.private_key, + pk.private_key.as_ref(), &hex!("04207060252933AC6E7A4A9B0EB2632C5A040A87257ADB869A3ECCC3D16B724F2647")[..] ); } @@ -160,7 +163,7 @@ fn decode_x25519_der() { #[test] #[cfg(feature = "alloc")] fn encode_ec_p256_der() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); let pk_encoded = pk.to_der().unwrap(); assert_eq!(EC_P256_DER_EXAMPLE, pk_encoded); } @@ -176,32 +179,32 @@ fn encode_ec_bignp256_der() { #[test] #[cfg(feature = "alloc")] fn encode_ed25519_der_v1() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(ED25519_DER_V1_EXAMPLE, pk.to_der().unwrap()); } #[test] #[cfg(all(feature = "alloc", feature = "subtle"))] fn encode_ed25519_der_v2() { - let private_key = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + let private_key = PrivateKeyInfoRef::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); let private_der = private_key.to_der().unwrap(); assert_eq!( private_key, - PrivateKeyInfo::try_from(private_der.as_ref()).unwrap() + PrivateKeyInfoRef::try_from(private_der.as_ref()).unwrap() ); } #[test] #[cfg(feature = "alloc")] fn encode_rsa_2048_der() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(RSA_2048_DER_EXAMPLE, &pk.to_der().unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_ec_p256_pem() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); assert_eq!(EC_P256_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } @@ -215,20 +218,20 @@ fn encode_ec_bignp256_pem() { #[test] #[cfg(feature = "pem")] fn encode_ed25519_pem() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(ED25519_PEM_V1_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_rsa_2048_pem() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(RSA_2048_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_x25519_pem() { - let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(X25519_DER_EXAMPLE).unwrap(); assert_eq!(X25519_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } diff --git a/pkcs8/tests/traits.rs b/pkcs8/tests/traits.rs index 4a603bb94..c9e63d124 100644 --- a/pkcs8/tests/traits.rs +++ b/pkcs8/tests/traits.rs @@ -3,7 +3,7 @@ #![cfg(any(feature = "pem", feature = "std"))] use der::Encode; -use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfo, Result, SecretDocument}; +use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfoRef, Result, SecretDocument}; #[cfg(feature = "pem")] use pkcs8::der::pem::LineEnding; @@ -14,7 +14,7 @@ use tempfile::tempdir; #[cfg(all(feature = "pem", feature = "std"))] use std::fs; -/// Ed25519 `PrivateKeyInfo` encoded as ASN.1 DER +/// Ed25519 `PrivateKeyInfoRef` encoded as ASN.1 DER const ED25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); /// Ed25519 private key encoded as PEM @@ -36,10 +36,10 @@ impl EncodePrivateKey for MockKey { } } -impl TryFrom> for MockKey { +impl TryFrom> for MockKey { type Error = Error; - fn try_from(pkcs8: PrivateKeyInfo<'_>) -> Result { + fn try_from(pkcs8: PrivateKeyInfoRef<'_>) -> Result { Ok(MockKey(pkcs8.to_der()?)) } } From 5136ffed5def8b1e67b0c7328a8a230790d6e761 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 6 Aug 2023 03:49:22 +0000 Subject: [PATCH 02/14] pkcs8: provide `PrivateKeyInfo` type alias with older API Signed-off-by: Arthur Gautier --- pkcs8/src/lib.rs | 2 +- pkcs8/src/private_key_info.rs | 55 +++++++++++++--------------- pkcs8/src/traits.rs | 14 +++---- pkcs8/tests/encrypted_private_key.rs | 6 +-- pkcs8/tests/private_key.rs | 30 +++++++-------- pkcs8/tests/traits.rs | 8 ++-- 6 files changed, 56 insertions(+), 59 deletions(-) diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index 6578e3a18..05d969172 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -85,7 +85,7 @@ pub(crate) mod encrypted_private_key_info; pub use crate::{ error::{Error, Result}, - private_key_info::{PrivateKeyInfo, PrivateKeyInfoRef}, + private_key_info::{PrivateKeyInfo, PrivateKeyInfoInner}, traits::DecodePrivateKey, version::Version, }; diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index 89146450d..07ec267a4 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -91,7 +91,7 @@ const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1; /// [RFC 5208 Section 5]: https://tools.ietf.org/html/rfc5208#section-5 /// [RFC 5958 Section 2]: https://datatracker.ietf.org/doc/html/rfc5958#section-2 #[derive(Clone)] -pub struct PrivateKeyInfo { +pub struct PrivateKeyInfoInner { /// X.509 `AlgorithmIdentifier` for the private key type. pub algorithm: AlgorithmIdentifier, @@ -102,8 +102,8 @@ pub struct PrivateKeyInfo { pub public_key: Option, } -impl PrivateKeyInfo { - /// Create a new PKCS#8 [`PrivateKeyInfo`] message. +impl PrivateKeyInfoInner { + /// Create a new PKCS#8 [`PrivateKeyInfoInner`] message. /// /// This is a helper method which initializes `attributes` and `public_key` /// to `None`, helpful if you aren't using those. @@ -126,7 +126,7 @@ impl PrivateKeyInfo { } } } -impl<'a, Params, Key> PrivateKeyInfo +impl<'a, Params, Key> PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, Key: From<&'a [u8]> + AsRef<[u8]>, @@ -163,7 +163,7 @@ where } } -impl<'a, Params, Key> PrivateKeyInfo +impl<'a, Params, Key> PrivateKeyInfoInner where Params: der::Choice<'a> + Encode, Key: AsRef<[u8]>, @@ -183,17 +183,14 @@ where } } -impl<'a, Params, Key> DecodeValue<'a> for PrivateKeyInfo +impl<'a, Params, Key> DecodeValue<'a> for PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, Key: From<&'a [u8]>, { type Error = der::Error; - fn decode_value>( - reader: &mut R, - header: Header, - ) -> der::Result> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { reader.read_nested(header.length, |reader| { // Parse and validate `version` INTEGER. let version = Version::decode(reader)?; @@ -234,7 +231,7 @@ where } } -impl<'a, Params, Key> EncodeValue for PrivateKeyInfo +impl<'a, Params, Key> EncodeValue for PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, Key: AsRef<[u8]>, @@ -255,14 +252,14 @@ where } } -impl<'a, Params, Key> Sequence<'a> for PrivateKeyInfo +impl<'a, Params, Key> Sequence<'a> for PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, Key: From<&'a [u8]> + AsRef<[u8]>, { } -impl<'a, Params, Key> TryFrom<&'a [u8]> for PrivateKeyInfo +impl<'a, Params, Key> TryFrom<&'a [u8]> for PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, Key: From<&'a [u8]> + AsRef<[u8]> + 'a, @@ -274,13 +271,13 @@ where } } -impl fmt::Debug for PrivateKeyInfo +impl fmt::Debug for PrivateKeyInfoInner where Params: fmt::Debug, Key: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PrivateKeyInfo") + f.debug_struct("PrivateKeyInfoInner") .field("version", &self.version()) .field("algorithm", &self.algorithm) .field("public_key", &self.public_key) @@ -289,38 +286,38 @@ where } #[cfg(feature = "alloc")] -impl<'a, Params, Key> TryFrom> for SecretDocument +impl<'a, Params, Key> TryFrom> for SecretDocument where Params: der::Choice<'a, Error = der::Error> + Encode, Key: From<&'a [u8]> + AsRef<[u8]>, { type Error = Error; - fn try_from(private_key: PrivateKeyInfo) -> Result { + fn try_from(private_key: PrivateKeyInfoInner) -> Result { SecretDocument::try_from(&private_key) } } #[cfg(feature = "alloc")] -impl<'a, Params, Key> TryFrom<&PrivateKeyInfo> for SecretDocument +impl<'a, Params, Key> TryFrom<&PrivateKeyInfoInner> for SecretDocument where Params: der::Choice<'a, Error = der::Error> + Encode, Key: From<&'a [u8]> + AsRef<[u8]>, { type Error = Error; - fn try_from(private_key: &PrivateKeyInfo) -> Result { + fn try_from(private_key: &PrivateKeyInfoInner) -> Result { Ok(Self::encode_msg(private_key)?) } } #[cfg(feature = "pem")] -impl PemLabel for PrivateKeyInfo { +impl PemLabel for PrivateKeyInfoInner { const PEM_LABEL: &'static str = "PRIVATE KEY"; } #[cfg(feature = "subtle")] -impl ConstantTimeEq for PrivateKeyInfo +impl ConstantTimeEq for PrivateKeyInfoInner where Params: Eq, Key: PartialEq + AsRef<[u8]>, @@ -336,7 +333,7 @@ where } #[cfg(feature = "subtle")] -impl Eq for PrivateKeyInfo +impl Eq for PrivateKeyInfoInner where Params: Eq, Key: AsRef<[u8]> + Eq, @@ -344,7 +341,7 @@ where } #[cfg(feature = "subtle")] -impl PartialEq for PrivateKeyInfo +impl PartialEq for PrivateKeyInfoInner where Params: Eq, Key: PartialEq + AsRef<[u8]>, @@ -354,19 +351,19 @@ where } } -/// [`PrivateKeyInfo`] with [`AnyRef`] algorithm parameters, and `&[u8]` key. -pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, &'a [u8]>; +/// [`PrivateKeyInfoInner`] with [`AnyRef`] algorithm parameters, and `&[u8]` key. +pub type PrivateKeyInfo<'a> = PrivateKeyInfoInner, &'a [u8]>; /// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and `Box<[u8]>` key. #[cfg(feature = "alloc")] -pub type PrivateKeyInfoOwned = PrivateKeyInfo>; +pub type PrivateKeyInfoOwned = PrivateKeyInfoInner>; #[cfg(feature = "alloc")] mod allocating { use super::*; use der::referenced::*; - impl<'a> RefToOwned<'a> for PrivateKeyInfoRef<'a> { + impl<'a> RefToOwned<'a> for PrivateKeyInfo<'a> { type Owned = PrivateKeyInfoOwned; fn ref_to_owned(&self) -> Self::Owned { PrivateKeyInfoOwned { @@ -378,9 +375,9 @@ mod allocating { } impl OwnedToRef for PrivateKeyInfoOwned { - type Borrowed<'a> = PrivateKeyInfoRef<'a>; + type Borrowed<'a> = PrivateKeyInfo<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { - PrivateKeyInfoRef { + PrivateKeyInfo { algorithm: self.algorithm.owned_to_ref(), private_key: self.private_key.owned_to_ref(), public_key: self.public_key.owned_to_ref(), diff --git a/pkcs8/src/traits.rs b/pkcs8/src/traits.rs index 07b0ac832..a38a78e6d 100644 --- a/pkcs8/src/traits.rs +++ b/pkcs8/src/traits.rs @@ -1,6 +1,6 @@ //! Traits for parsing objects from PKCS#8 encoded documents -use crate::{Error, PrivateKeyInfoRef, Result}; +use crate::{Error, PrivateKeyInfo, Result}; #[cfg(feature = "alloc")] use der::SecretDocument; @@ -46,7 +46,7 @@ pub trait DecodePrivateKey: Sized { fn from_pkcs8_pem(s: &str) -> Result { // Validate PEM label let label = pem::decode_label(s.as_bytes())?; - PrivateKeyInfoRef::validate_pem_label(label)?; + PrivateKeyInfo::validate_pem_label(label)?; let doc = SecretDocument::from_pem(s)?.1; Self::from_pkcs8_der(doc.as_bytes()) @@ -78,17 +78,17 @@ pub trait DecodePrivateKey: Sized { #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs8_pem_file(path: impl AsRef) -> Result { let (label, doc) = SecretDocument::read_pem_file(path)?; - PrivateKeyInfoRef::validate_pem_label(&label)?; + PrivateKeyInfo::validate_pem_label(&label)?; Self::from_pkcs8_der(doc.as_bytes()) } } impl DecodePrivateKey for T where - T: for<'a> TryFrom, Error = Error>, + T: for<'a> TryFrom, Error = Error>, { fn from_pkcs8_der(bytes: &[u8]) -> Result { - Self::try_from(PrivateKeyInfoRef::try_from(bytes)?) + Self::try_from(PrivateKeyInfo::try_from(bytes)?) } } @@ -113,7 +113,7 @@ pub trait EncodePrivateKey { #[cfg(feature = "pem")] fn to_pkcs8_pem(&self, line_ending: LineEnding) -> Result> { let doc = self.to_pkcs8_der()?; - Ok(doc.to_pem(PrivateKeyInfoRef::PEM_LABEL, line_ending)?) + Ok(doc.to_pem(PrivateKeyInfo::PEM_LABEL, line_ending)?) } /// Serialize this private key as an encrypted PEM-encoded PKCS#8 private @@ -139,6 +139,6 @@ pub trait EncodePrivateKey { #[cfg(all(feature = "pem", feature = "std"))] fn write_pkcs8_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs8_der()?; - Ok(doc.write_pem_file(path, PrivateKeyInfoRef::PEM_LABEL, line_ending)?) + Ok(doc.write_pem_file(path, PrivateKeyInfo::PEM_LABEL, line_ending)?) } } diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index 716ba97da..cd7ad6b0a 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -3,7 +3,7 @@ #![cfg(feature = "pkcs5")] use hex_literal::hex; -use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo, PrivateKeyInfoRef}; +use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo, PrivateKeyInfo}; #[cfg(feature = "alloc")] use der::Encode; @@ -248,7 +248,7 @@ fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(pbes2_params, PASSWORD) .unwrap(); @@ -269,7 +269,7 @@ fn encrypt_ed25519_der_encpriv_aes256_scrypt() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(scrypt_params, PASSWORD) .unwrap(); diff --git a/pkcs8/tests/private_key.rs b/pkcs8/tests/private_key.rs index 5572cd722..cba2308f3 100644 --- a/pkcs8/tests/private_key.rs +++ b/pkcs8/tests/private_key.rs @@ -2,7 +2,7 @@ use der::asn1::ObjectIdentifier; use hex_literal::hex; -use pkcs8::{PrivateKeyInfoRef, Version}; +use pkcs8::{PrivateKeyInfo, Version}; #[cfg(feature = "alloc")] use der::Encode; @@ -49,7 +49,7 @@ const X25519_PEM_EXAMPLE: &str = include_str!("examples/x25519-priv.pem"); #[test] fn decode_ec_p256_der() { - let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.2.840.10045.2.1".parse().unwrap()); @@ -98,7 +98,7 @@ fn decode_ec_bignp256_der() { // https://datatracker.ietf.org/doc/html/rfc8410#section-10.3 #[test] fn decode_ed25519_der_v1() { - let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -122,7 +122,7 @@ fn decode_ed25519_der_v2() { const PUB_KEY: [u8; 32] = hex!("19BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1"); - let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V2); assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -135,7 +135,7 @@ fn decode_ed25519_der_v2() { #[test] fn decode_rsa_2048_der() { - let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.2.840.113549.1.1.1".parse().unwrap()); assert!(pk.algorithm.parameters.unwrap().is_null()); @@ -147,7 +147,7 @@ fn decode_rsa_2048_der() { #[test] fn decode_x25519_der() { - let pk = PrivateKeyInfoRef::try_from(X25519_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.3.101.110".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -163,7 +163,7 @@ fn decode_x25519_der() { #[test] #[cfg(feature = "alloc")] fn encode_ec_p256_der() { - let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); let pk_encoded = pk.to_der().unwrap(); assert_eq!(EC_P256_DER_EXAMPLE, pk_encoded); } @@ -179,32 +179,32 @@ fn encode_ec_bignp256_der() { #[test] #[cfg(feature = "alloc")] fn encode_ed25519_der_v1() { - let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(ED25519_DER_V1_EXAMPLE, pk.to_der().unwrap()); } #[test] #[cfg(all(feature = "alloc", feature = "subtle"))] fn encode_ed25519_der_v2() { - let private_key = PrivateKeyInfoRef::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + let private_key = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); let private_der = private_key.to_der().unwrap(); assert_eq!( private_key, - PrivateKeyInfoRef::try_from(private_der.as_ref()).unwrap() + PrivateKeyInfo::try_from(private_der.as_ref()).unwrap() ); } #[test] #[cfg(feature = "alloc")] fn encode_rsa_2048_der() { - let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(RSA_2048_DER_EXAMPLE, &pk.to_der().unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_ec_p256_pem() { - let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); assert_eq!(EC_P256_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } @@ -218,20 +218,20 @@ fn encode_ec_bignp256_pem() { #[test] #[cfg(feature = "pem")] fn encode_ed25519_pem() { - let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(ED25519_PEM_V1_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_rsa_2048_pem() { - let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(RSA_2048_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_x25519_pem() { - let pk = PrivateKeyInfoRef::try_from(X25519_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); assert_eq!(X25519_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } diff --git a/pkcs8/tests/traits.rs b/pkcs8/tests/traits.rs index c9e63d124..4a603bb94 100644 --- a/pkcs8/tests/traits.rs +++ b/pkcs8/tests/traits.rs @@ -3,7 +3,7 @@ #![cfg(any(feature = "pem", feature = "std"))] use der::Encode; -use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfoRef, Result, SecretDocument}; +use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfo, Result, SecretDocument}; #[cfg(feature = "pem")] use pkcs8::der::pem::LineEnding; @@ -14,7 +14,7 @@ use tempfile::tempdir; #[cfg(all(feature = "pem", feature = "std"))] use std::fs; -/// Ed25519 `PrivateKeyInfoRef` encoded as ASN.1 DER +/// Ed25519 `PrivateKeyInfo` encoded as ASN.1 DER const ED25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); /// Ed25519 private key encoded as PEM @@ -36,10 +36,10 @@ impl EncodePrivateKey for MockKey { } } -impl TryFrom> for MockKey { +impl TryFrom> for MockKey { type Error = Error; - fn try_from(pkcs8: PrivateKeyInfoRef<'_>) -> Result { + fn try_from(pkcs8: PrivateKeyInfo<'_>) -> Result { Ok(MockKey(pkcs8.to_der()?)) } } From de558e8df453043fbc40c56b447c02dbe87e6bd1 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 7 Aug 2023 16:11:10 +0000 Subject: [PATCH 03/14] pkcs8: `pem` pulls `alloc` feature Signed-off-by: Arthur Gautier --- pkcs8/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index 05d969172..84ec06dec 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -70,7 +70,7 @@ //! [PKCS#5v2 Password Based Encryption Scheme 2 (RFC 8018)]: https://tools.ietf.org/html/rfc8018#section-6.2 //! [scrypt]: https://en.wikipedia.org/wiki/Scrypt -#[cfg(feature = "pem")] +#[cfg(feature = "alloc")] extern crate alloc; #[cfg(feature = "std")] extern crate std; From e25f4da975121bc0a72bfa6fa58e56bf6cb57098 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 9 Aug 2023 21:27:11 +0000 Subject: [PATCH 04/14] pkcs8: split `EncryptedPrivateKeyInfo` Signed-off-by: Arthur Gautier --- pkcs8/src/encrypted_private_key_info.rs | 73 +++++++++++++++++-------- pkcs8/src/lib.rs | 7 ++- pkcs8/src/private_key_info.rs | 9 +-- pkcs8/src/traits.rs | 10 ++-- pkcs8/tests/encrypted_private_key.rs | 23 +++++--- 5 files changed, 79 insertions(+), 43 deletions(-) diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs index 19575bf2f..b3febeca9 100644 --- a/pkcs8/src/encrypted_private_key_info.rs +++ b/pkcs8/src/encrypted_private_key_info.rs @@ -9,7 +9,7 @@ use der::{ use pkcs5::EncryptionScheme; #[cfg(feature = "alloc")] -use der::SecretDocument; +use {alloc::boxed::Box, der::SecretDocument}; #[cfg(feature = "encryption")] use {pkcs5::pbes2, rand_core::CryptoRngCore}; @@ -37,23 +37,26 @@ use der::pem::PemLabel; /// /// [RFC 5208 Section 6]: https://tools.ietf.org/html/rfc5208#section-6 #[derive(Clone, Eq, PartialEq)] -pub struct EncryptedPrivateKeyInfo<'a> { +pub struct EncryptedPrivateKeyInfo { /// Algorithm identifier describing a password-based symmetric encryption /// scheme used to encrypt the `encrypted_data` field. pub encryption_algorithm: EncryptionScheme, /// Private key data - pub encrypted_data: &'a [u8], + pub encrypted_data: Data, } -impl<'a> EncryptedPrivateKeyInfo<'a> { +impl<'a, Data> EncryptedPrivateKeyInfo +where + Data: AsRef<[u8]> + From<&'a [u8]>, +{ /// Attempt to decrypt this encrypted private key using the provided /// password to derive an encryption key. #[cfg(feature = "encryption")] pub fn decrypt(&self, password: impl AsRef<[u8]>) -> Result { Ok(self .encryption_algorithm - .decrypt(password, self.encrypted_data)? + .decrypt(password, self.encrypted_data.as_ref())? .try_into()?) } @@ -66,7 +69,7 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { doc: &[u8], ) -> Result { let pbes2_params = pbes2::Parameters::recommended(rng); - EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, doc) + EncryptedPrivateKeyInfoOwned::encrypt_with(pbes2_params, password, doc) } /// Encrypt this private key using a symmetric encryption key derived @@ -81,44 +84,53 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { EncryptedPrivateKeyInfo { encryption_algorithm: pbes2_params.into(), - encrypted_data: &encrypted_data, + encrypted_data, } .try_into() } } -impl<'a> DecodeValue<'a> for EncryptedPrivateKeyInfo<'a> { +impl<'a, Data> DecodeValue<'a> for EncryptedPrivateKeyInfo +where + Data: From<&'a [u8]>, +{ type Error = der::Error; - fn decode_value>( - reader: &mut R, - header: Header, - ) -> der::Result> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { reader.read_nested(header.length, |reader| { Ok(Self { encryption_algorithm: reader.decode()?, - encrypted_data: OctetStringRef::decode(reader)?.as_bytes(), + encrypted_data: OctetStringRef::decode(reader)?.as_bytes().into(), }) }) } } -impl EncodeValue for EncryptedPrivateKeyInfo<'_> { +impl EncodeValue for EncryptedPrivateKeyInfo +where + Data: AsRef<[u8]>, +{ fn value_len(&self) -> der::Result { self.encryption_algorithm.encoded_len()? - + OctetStringRef::new(self.encrypted_data)?.encoded_len()? + + OctetStringRef::new(self.encrypted_data.as_ref())?.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.encryption_algorithm.encode(writer)?; - OctetStringRef::new(self.encrypted_data)?.encode(writer)?; + OctetStringRef::new(self.encrypted_data.as_ref())?.encode(writer)?; Ok(()) } } -impl<'a> Sequence<'a> for EncryptedPrivateKeyInfo<'a> {} +impl<'a, Data> Sequence<'a> for EncryptedPrivateKeyInfo where + Data: AsRef<[u8]> + From<&'a [u8]> +{ +} -impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> { +impl<'a, Data> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo +where + Data: AsRef<[u8]> + From<&'a [u8]> + 'a, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -126,7 +138,7 @@ impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> { } } -impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> { +impl fmt::Debug for EncryptedPrivateKeyInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EncryptedPrivateKeyInfo") .field("encryption_algorithm", &self.encryption_algorithm) @@ -135,24 +147,37 @@ impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> { } #[cfg(feature = "alloc")] -impl TryFrom> for SecretDocument { +impl<'a, Data> TryFrom> for SecretDocument +where + Data: AsRef<[u8]> + From<&'a [u8]>, +{ type Error = Error; - fn try_from(encrypted_private_key: EncryptedPrivateKeyInfo<'_>) -> Result { + fn try_from(encrypted_private_key: EncryptedPrivateKeyInfo) -> Result { SecretDocument::try_from(&encrypted_private_key) } } #[cfg(feature = "alloc")] -impl TryFrom<&EncryptedPrivateKeyInfo<'_>> for SecretDocument { +impl<'a, Data> TryFrom<&EncryptedPrivateKeyInfo> for SecretDocument +where + Data: AsRef<[u8]> + From<&'a [u8]>, +{ type Error = Error; - fn try_from(encrypted_private_key: &EncryptedPrivateKeyInfo<'_>) -> Result { + fn try_from(encrypted_private_key: &EncryptedPrivateKeyInfo) -> Result { Ok(Self::encode_msg(encrypted_private_key)?) } } #[cfg(feature = "pem")] -impl PemLabel for EncryptedPrivateKeyInfo<'_> { +impl PemLabel for EncryptedPrivateKeyInfo { const PEM_LABEL: &'static str = "ENCRYPTED PRIVATE KEY"; } + +/// [`EncryptedPrivateKeyInfo`] with `&[u8]` encrypted data. +pub type EncryptedPrivateKeyInfoRef<'a> = EncryptedPrivateKeyInfo<&'a [u8]>; + +#[cfg(feature = "alloc")] +/// [`EncryptedPrivateKeyInfo`] with `Box<[u8]>` encrypted data. +pub type EncryptedPrivateKeyInfoOwned = EncryptedPrivateKeyInfo>; diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index 84ec06dec..f7980d670 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -104,8 +104,13 @@ pub use { #[cfg(feature = "pem")] pub use der::pem::LineEnding; +#[cfg(all(feature = "alloc", feature = "pkcs5"))] +pub use encrypted_private_key_info::EncryptedPrivateKeyInfoOwned; #[cfg(feature = "pkcs5")] -pub use {encrypted_private_key_info::EncryptedPrivateKeyInfo, pkcs5}; +pub use { + encrypted_private_key_info::{EncryptedPrivateKeyInfo, EncryptedPrivateKeyInfoRef}, + pkcs5, +}; #[cfg(feature = "rand_core")] pub use rand_core; diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index 07ec267a4..f62212ee3 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -17,7 +17,8 @@ use { #[cfg(feature = "encryption")] use { - crate::EncryptedPrivateKeyInfo, der::zeroize::Zeroizing, pkcs5::pbes2, rand_core::CryptoRngCore, + crate::EncryptedPrivateKeyInfoRef, der::zeroize::Zeroizing, pkcs5::pbes2, + rand_core::CryptoRngCore, }; #[cfg(feature = "pem")] @@ -129,7 +130,7 @@ impl PrivateKeyInfoInner { impl<'a, Params, Key> PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, - Key: From<&'a [u8]> + AsRef<[u8]>, + Key: From<&'a [u8]> + AsRef<[u8]> + 'a, { /// Encrypt this private key using a symmetric encryption key derived /// from the provided password. @@ -147,7 +148,7 @@ where password: impl AsRef<[u8]>, ) -> Result { let der = Zeroizing::new(self.to_der()?); - EncryptedPrivateKeyInfo::encrypt(rng, password, der.as_ref()) + EncryptedPrivateKeyInfoRef::encrypt(rng, password, der.as_ref()) } /// Encrypt this private key using a symmetric encryption key derived @@ -159,7 +160,7 @@ where password: impl AsRef<[u8]>, ) -> Result { let der = Zeroizing::new(self.to_der()?); - EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, der.as_ref()) + EncryptedPrivateKeyInfoRef::encrypt_with(pbes2_params, password, der.as_ref()) } } diff --git a/pkcs8/src/traits.rs b/pkcs8/src/traits.rs index a38a78e6d..9b5b029dc 100644 --- a/pkcs8/src/traits.rs +++ b/pkcs8/src/traits.rs @@ -6,7 +6,7 @@ use crate::{Error, PrivateKeyInfo, Result}; use der::SecretDocument; #[cfg(feature = "encryption")] -use {crate::EncryptedPrivateKeyInfo, rand_core::CryptoRngCore}; +use {crate::EncryptedPrivateKeyInfoRef, rand_core::CryptoRngCore}; #[cfg(feature = "pem")] use { @@ -31,7 +31,7 @@ pub trait DecodePrivateKey: Sized { /// (binary format) and attempt to decrypt it using the provided password. #[cfg(feature = "encryption")] fn from_pkcs8_encrypted_der(bytes: &[u8], password: impl AsRef<[u8]>) -> Result { - let doc = EncryptedPrivateKeyInfo::try_from(bytes)?.decrypt(password)?; + let doc = EncryptedPrivateKeyInfoRef::try_from(bytes)?.decrypt(password)?; Self::from_pkcs8_der(doc.as_bytes()) } @@ -63,7 +63,7 @@ pub trait DecodePrivateKey: Sized { #[cfg(all(feature = "encryption", feature = "pem"))] fn from_pkcs8_encrypted_pem(s: &str, password: impl AsRef<[u8]>) -> Result { let (label, doc) = SecretDocument::from_pem(s)?; - EncryptedPrivateKeyInfo::validate_pem_label(label)?; + EncryptedPrivateKeyInfoRef::validate_pem_label(label)?; Self::from_pkcs8_encrypted_der(doc.as_bytes(), password) } @@ -106,7 +106,7 @@ pub trait EncodePrivateKey { rng: &mut impl CryptoRngCore, password: impl AsRef<[u8]>, ) -> Result { - EncryptedPrivateKeyInfo::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes()) + EncryptedPrivateKeyInfoRef::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes()) } /// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`]. @@ -126,7 +126,7 @@ pub trait EncodePrivateKey { line_ending: LineEnding, ) -> Result> { let doc = self.to_pkcs8_encrypted_der(rng, password)?; - Ok(doc.to_pem(EncryptedPrivateKeyInfo::PEM_LABEL, line_ending)?) + Ok(doc.to_pem(EncryptedPrivateKeyInfoRef::PEM_LABEL, line_ending)?) } /// Write ASN.1 DER-encoded PKCS#8 private key to the given path diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index cd7ad6b0a..6d97a4233 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -3,7 +3,7 @@ #![cfg(feature = "pkcs5")] use hex_literal::hex; -use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo, PrivateKeyInfo}; +use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfoRef, PrivateKeyInfo}; #[cfg(feature = "alloc")] use der::Encode; @@ -101,7 +101,7 @@ const PASSWORD: &[u8] = b"hunter42"; // Bad password; don't actually use outside #[test] fn decode_ed25519_encpriv_aes128_pbkdf2_sha1_der() { - let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES128_PBKDF2_SHA1_EXAMPLE).unwrap(); + let pk = EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES128_PBKDF2_SHA1_EXAMPLE).unwrap(); assert_eq!( pk.encryption_algorithm.oid(), @@ -133,7 +133,8 @@ fn decode_ed25519_encpriv_aes128_pbkdf2_sha1_der() { #[test] fn decode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { - let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + let pk = + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); assert_eq!( pk.encryption_algorithm.oid(), @@ -167,7 +168,7 @@ fn decode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { #[test] fn decrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { let enc_pk = - EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } @@ -175,7 +176,7 @@ fn decrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { #[cfg(feature = "encryption")] #[test] fn decrypt_ed25519_der_encpriv_aes256_scrypt() { - let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_SCRYPT_EXAMPLE).unwrap(); + let enc_pk = EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES256_SCRYPT_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } @@ -280,7 +281,8 @@ fn encrypt_ed25519_der_encpriv_aes256_scrypt() { #[test] #[cfg(feature = "alloc")] fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { - let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + let pk = + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); assert_eq!( ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE, &pk.to_der().unwrap() @@ -290,7 +292,8 @@ fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { #[test] #[cfg(feature = "pem")] fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_pem() { - let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + let pk = + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); assert_eq!( ED25519_PEM_AES256_PBKDF2_SHA256_EXAMPLE, pk.to_pem(Default::default()).unwrap() @@ -300,7 +303,8 @@ fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_pem() { #[test] #[cfg(feature = "3des")] fn decrypt_ed25519_der_encpriv_des3_pbkdf2_sha256() { - let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_DES3_PBKDF2_SHA256_EXAMPLE).unwrap(); + let enc_pk = + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_DES3_PBKDF2_SHA256_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } @@ -308,7 +312,8 @@ fn decrypt_ed25519_der_encpriv_des3_pbkdf2_sha256() { #[test] #[cfg(feature = "des-insecure")] fn decrypt_ed25519_der_encpriv_des_pbkdf2_sha256() { - let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_DES_PBKDF2_SHA256_EXAMPLE).unwrap(); + let enc_pk = + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_DES_PBKDF2_SHA256_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } From d7993842fa153b0403840a1cee7301b907377afd Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 18 Aug 2024 21:52:30 +0000 Subject: [PATCH 05/14] pkcs8: Fixup tests Signed-off-by: Arthur Gautier --- pkcs8/tests/encrypted_private_key.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index 6d97a4233..8d6541b9e 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -11,6 +11,9 @@ use der::Encode; #[cfg(feature = "pem")] use der::EncodePem; +#[cfg(feature = "encryption")] +use pkcs8::EncryptedPrivateKeyInfoOwned; + /// Ed25519 PKCS#8 private key plaintext encoded as ASN.1 DER #[cfg(feature = "encryption")] const ED25519_DER_PLAINTEXT_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); @@ -184,7 +187,8 @@ fn decrypt_ed25519_der_encpriv_aes256_scrypt() { #[cfg(feature = "encryption")] #[test] fn decrypt_ed25519_der_encpriv_aes128_gcm_scrypt() { - let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES128_GCM_SCRYPT_EXAMPLE).unwrap(); + let enc_pk = + EncryptedPrivateKeyInfoOwned::try_from(ED25519_DER_AES128_GCM_SCRYPT_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } @@ -213,7 +217,8 @@ fn encrypt_ed25519_der_encpriv_aes128_gcm_scrypt() { #[cfg(feature = "encryption")] #[test] fn decrypt_ed25519_der_encpriv_aes256_gcm_scrypt() { - let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_GCM_SCRYPT_EXAMPLE).unwrap(); + let enc_pk = + EncryptedPrivateKeyInfoOwned::try_from(ED25519_DER_AES256_GCM_SCRYPT_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } From 2a95a85bf4120080e84c4173e17f57f8da4cc2b4 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 06:40:59 +0000 Subject: [PATCH 06/14] pkcs8: use OctetString/BitString Signed-off-by: Arthur Gautier --- pkcs8/src/private_key_info.rs | 149 ++++++++++++++++++++-------------- pkcs8/tests/private_key.rs | 12 +-- 2 files changed, 96 insertions(+), 65 deletions(-) diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index f62212ee3..646385555 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -4,15 +4,15 @@ use crate::{Error, Result, Version}; use core::fmt; use der::{ asn1::{AnyRef, BitStringRef, ContextSpecific, OctetStringRef}, - Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, TagMode, TagNumber, - Writer, + Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence, TagMode, + TagNumber, Writer, }; use spki::AlgorithmIdentifier; #[cfg(feature = "alloc")] -use { - alloc::boxed::Box, - der::{asn1::Any, SecretDocument}, +use der::{ + asn1::{Any, BitString, OctetString}, + SecretDocument, }; #[cfg(feature = "encryption")] @@ -92,7 +92,7 @@ const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1; /// [RFC 5208 Section 5]: https://tools.ietf.org/html/rfc5208#section-5 /// [RFC 5958 Section 2]: https://datatracker.ietf.org/doc/html/rfc5958#section-2 #[derive(Clone)] -pub struct PrivateKeyInfoInner { +pub struct PrivateKeyInfoInner { /// X.509 `AlgorithmIdentifier` for the private key type. pub algorithm: AlgorithmIdentifier, @@ -100,10 +100,10 @@ pub struct PrivateKeyInfoInner { pub private_key: Key, /// Public key data, optionally available if version is V2. - pub public_key: Option, + pub public_key: Option, } -impl PrivateKeyInfoInner { +impl PrivateKeyInfoInner { /// Create a new PKCS#8 [`PrivateKeyInfoInner`] message. /// /// This is a helper method which initializes `attributes` and `public_key` @@ -127,10 +127,14 @@ impl PrivateKeyInfoInner { } } } -impl<'a, Params, Key> PrivateKeyInfoInner + +impl<'a, Params, Key, PubKey> PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, - Key: From<&'a [u8]> + AsRef<[u8]> + 'a, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, { /// Encrypt this private key using a symmetric encryption key derived /// from the provided password. @@ -164,30 +168,29 @@ where } } -impl<'a, Params, Key> PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> PrivateKeyInfoInner where Params: der::Choice<'a> + Encode, - Key: AsRef<[u8]>, + PubKey: BitStringLike, { /// Get a `BIT STRING` representation of the public key, if present. - fn public_key_bit_string(&self) -> der::Result>>> { - self.public_key - .as_ref() - .map(|pk| { - BitStringRef::from_bytes(pk.as_ref()).map(|value| ContextSpecific { - tag_number: PUBLIC_KEY_TAG, - tag_mode: TagMode::Implicit, - value, - }) - }) - .transpose() + fn public_key_bit_string(&self) -> Option>> { + self.public_key.as_ref().map(|pk| { + let value = pk.as_bit_string(); + ContextSpecific { + tag_number: PUBLIC_KEY_TAG, + tag_mode: TagMode::Implicit, + value, + } + }) } } -impl<'a, Params, Key> DecodeValue<'a> for PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> DecodeValue<'a> for PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, - Key: From<&'a [u8]>, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, { type Error = der::Error; @@ -196,16 +199,9 @@ where // Parse and validate `version` INTEGER. let version = Version::decode(reader)?; let algorithm = reader.decode()?; - let private_key: &[u8] = OctetStringRef::decode(reader)?.into(); - let private_key = Key::try_from(private_key)?; - let public_key = reader - .context_specific::>(PUBLIC_KEY_TAG, TagMode::Implicit)? - .map(|bs| { - bs.as_bytes() - .ok_or_else(|| der::Tag::BitString.value_error()) - .map(Key::from) - }) - .transpose()?; + let private_key = Key::decode(reader)?; + let public_key = + reader.context_specific::(PUBLIC_KEY_TAG, TagMode::Implicit)?; if version.has_public_key() != public_key.is_some() { return Err(reader.error( @@ -232,38 +228,45 @@ where } } -impl<'a, Params, Key> EncodeValue for PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> EncodeValue for PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, - Key: AsRef<[u8]>, + Key: EncodeValue + FixedTag, + PubKey: BitStringLike, { fn value_len(&self) -> der::Result { self.version().encoded_len()? + self.algorithm.encoded_len()? - + OctetStringRef::new(self.private_key.as_ref())?.encoded_len()? - + self.public_key_bit_string()?.encoded_len()? + + self.private_key.encoded_len()? + + self.public_key_bit_string().encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.version().encode(writer)?; self.algorithm.encode(writer)?; - OctetStringRef::new(self.private_key.as_ref())?.encode(writer)?; - self.public_key_bit_string()?.encode(writer)?; + self.private_key.encode(writer)?; + self.public_key_bit_string().encode(writer)?; Ok(()) } } -impl<'a, Params, Key> Sequence<'a> for PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> Sequence<'a> for PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, - Key: From<&'a [u8]> + AsRef<[u8]>, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, { } -impl<'a, Params, Key> TryFrom<&'a [u8]> for PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> TryFrom<&'a [u8]> for PrivateKeyInfoInner where Params: der::Choice<'a, Error = der::Error> + Encode, - Key: From<&'a [u8]> + AsRef<[u8]> + 'a, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, { type Error = Error; @@ -272,10 +275,10 @@ where } } -impl fmt::Debug for PrivateKeyInfoInner +impl fmt::Debug for PrivateKeyInfoInner where Params: fmt::Debug, - Key: fmt::Debug, + PubKey: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PrivateKeyInfoInner") @@ -287,41 +290,48 @@ where } #[cfg(feature = "alloc")] -impl<'a, Params, Key> TryFrom> for SecretDocument +impl<'a, Params, Key, PubKey> TryFrom> for SecretDocument where Params: der::Choice<'a, Error = der::Error> + Encode, - Key: From<&'a [u8]> + AsRef<[u8]>, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, { type Error = Error; - fn try_from(private_key: PrivateKeyInfoInner) -> Result { + fn try_from(private_key: PrivateKeyInfoInner) -> Result { SecretDocument::try_from(&private_key) } } #[cfg(feature = "alloc")] -impl<'a, Params, Key> TryFrom<&PrivateKeyInfoInner> for SecretDocument +impl<'a, Params, Key, PubKey> TryFrom<&PrivateKeyInfoInner> for SecretDocument where Params: der::Choice<'a, Error = der::Error> + Encode, - Key: From<&'a [u8]> + AsRef<[u8]>, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, { type Error = Error; - fn try_from(private_key: &PrivateKeyInfoInner) -> Result { + fn try_from(private_key: &PrivateKeyInfoInner) -> Result { Ok(Self::encode_msg(private_key)?) } } #[cfg(feature = "pem")] -impl PemLabel for PrivateKeyInfoInner { +impl PemLabel for PrivateKeyInfoInner { const PEM_LABEL: &'static str = "PRIVATE KEY"; } #[cfg(feature = "subtle")] -impl ConstantTimeEq for PrivateKeyInfoInner +impl ConstantTimeEq for PrivateKeyInfoInner where Params: Eq, Key: PartialEq + AsRef<[u8]>, + PubKey: PartialEq, { fn ct_eq(&self, other: &Self) -> Choice { // NOTE: public fields are not compared in constant time @@ -334,18 +344,20 @@ where } #[cfg(feature = "subtle")] -impl Eq for PrivateKeyInfoInner +impl Eq for PrivateKeyInfoInner where Params: Eq, Key: AsRef<[u8]> + Eq, + PubKey: Eq, { } #[cfg(feature = "subtle")] -impl PartialEq for PrivateKeyInfoInner +impl PartialEq for PrivateKeyInfoInner where Params: Eq, Key: PartialEq + AsRef<[u8]>, + PubKey: PartialEq, { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() @@ -353,17 +365,36 @@ where } /// [`PrivateKeyInfoInner`] with [`AnyRef`] algorithm parameters, and `&[u8]` key. -pub type PrivateKeyInfo<'a> = PrivateKeyInfoInner, &'a [u8]>; +pub type PrivateKeyInfo<'a> = PrivateKeyInfoInner, OctetStringRef<'a>, BitStringRef<'a>>; /// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and `Box<[u8]>` key. #[cfg(feature = "alloc")] -pub type PrivateKeyInfoOwned = PrivateKeyInfoInner>; +pub type PrivateKeyInfoOwned = PrivateKeyInfoInner; + +/// [`BitStringLike`] marks object that will act like a BitString. +/// +/// It will allow to get a [`BitStringRef`] that points back to the underlying bytes. +pub trait BitStringLike { + fn as_bit_string(&self) -> BitStringRef<'_>; +} + +impl<'a> BitStringLike for BitStringRef<'a> { + fn as_bit_string(&self) -> BitStringRef<'_> { + BitStringRef::from(self) + } +} #[cfg(feature = "alloc")] mod allocating { use super::*; use der::referenced::*; + impl BitStringLike for BitString { + fn as_bit_string(&self) -> BitStringRef<'_> { + BitStringRef::from(self) + } + } + impl<'a> RefToOwned<'a> for PrivateKeyInfo<'a> { type Owned = PrivateKeyInfoOwned; fn ref_to_owned(&self) -> Self::Owned { diff --git a/pkcs8/tests/private_key.rs b/pkcs8/tests/private_key.rs index cba2308f3..002112c2d 100644 --- a/pkcs8/tests/private_key.rs +++ b/pkcs8/tests/private_key.rs @@ -1,6 +1,6 @@ //! PKCS#8 private key tests -use der::asn1::ObjectIdentifier; +use der::asn1::{ObjectIdentifier, OctetStringRef}; use hex_literal::hex; use pkcs8::{PrivateKeyInfo, Version}; @@ -90,7 +90,10 @@ fn decode_ec_bignp256_der() { // $ openssl asn1parse -inform der -in tests/examples/bign256-priv.der assert_eq!( pk.private_key, - &hex!("1F66B5B84B7339674533F0329C74F21834281FED0732429E0C79235FC273E269") + OctetStringRef::new(&hex!( + "1F66B5B84B7339674533F0329C74F21834281FED0732429E0C79235FC273E269" + )) + .unwrap() ) } @@ -127,10 +130,7 @@ fn decode_ed25519_der_v2() { assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); assert_eq!(pk.private_key.as_ref(), PRIV_KEY); - assert_eq!( - pk.public_key.as_ref().map(|p| p.as_ref()), - Some(&PUB_KEY[..]) - ); + assert_eq!(pk.public_key.and_then(|p| p.as_bytes()), Some(&PUB_KEY[..])); } #[test] From 8ab1b6afe6b5b3e553d48f0bded09f67de689b4b Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 17:28:59 +0000 Subject: [PATCH 07/14] pkcs8: `PrivateKeyInfo` -> `PrivateKeyInfoRef` Signed-off-by: Arthur Gautier --- pkcs8/src/lib.rs | 2 +- pkcs8/src/private_key_info.rs | 50 ++++++++++++++-------------- pkcs8/src/traits.rs | 14 ++++---- pkcs8/tests/encrypted_private_key.rs | 10 +++--- pkcs8/tests/private_key.rs | 36 ++++++++++---------- pkcs8/tests/traits.rs | 8 ++--- 6 files changed, 60 insertions(+), 60 deletions(-) diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index f7980d670..734a2dd21 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -85,7 +85,7 @@ pub(crate) mod encrypted_private_key_info; pub use crate::{ error::{Error, Result}, - private_key_info::{PrivateKeyInfo, PrivateKeyInfoInner}, + private_key_info::{PrivateKeyInfo, PrivateKeyInfoRef}, traits::DecodePrivateKey, version::Version, }; diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index 646385555..9d6392e99 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -92,7 +92,7 @@ const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1; /// [RFC 5208 Section 5]: https://tools.ietf.org/html/rfc5208#section-5 /// [RFC 5958 Section 2]: https://datatracker.ietf.org/doc/html/rfc5958#section-2 #[derive(Clone)] -pub struct PrivateKeyInfoInner { +pub struct PrivateKeyInfo { /// X.509 `AlgorithmIdentifier` for the private key type. pub algorithm: AlgorithmIdentifier, @@ -103,8 +103,8 @@ pub struct PrivateKeyInfoInner { pub public_key: Option, } -impl PrivateKeyInfoInner { - /// Create a new PKCS#8 [`PrivateKeyInfoInner`] message. +impl PrivateKeyInfo { + /// Create a new PKCS#8 [`PrivateKeyInfo`] message. /// /// This is a helper method which initializes `attributes` and `public_key` /// to `None`, helpful if you aren't using those. @@ -128,7 +128,7 @@ impl PrivateKeyInfoInner { } } -impl<'a, Params, Key, PubKey> PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> PrivateKeyInfo where Params: der::Choice<'a, Error = der::Error> + Encode, Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, @@ -168,7 +168,7 @@ where } } -impl<'a, Params, Key, PubKey> PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> PrivateKeyInfo where Params: der::Choice<'a> + Encode, PubKey: BitStringLike, @@ -186,7 +186,7 @@ where } } -impl<'a, Params, Key, PubKey> DecodeValue<'a> for PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> DecodeValue<'a> for PrivateKeyInfo where Params: der::Choice<'a, Error = der::Error> + Encode, Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, @@ -228,7 +228,7 @@ where } } -impl<'a, Params, Key, PubKey> EncodeValue for PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> EncodeValue for PrivateKeyInfo where Params: der::Choice<'a, Error = der::Error> + Encode, Key: EncodeValue + FixedTag, @@ -250,7 +250,7 @@ where } } -impl<'a, Params, Key, PubKey> Sequence<'a> for PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> Sequence<'a> for PrivateKeyInfo where Params: der::Choice<'a, Error = der::Error> + Encode, Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, @@ -260,7 +260,7 @@ where { } -impl<'a, Params, Key, PubKey> TryFrom<&'a [u8]> for PrivateKeyInfoInner +impl<'a, Params, Key, PubKey> TryFrom<&'a [u8]> for PrivateKeyInfo where Params: der::Choice<'a, Error = der::Error> + Encode, Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, @@ -275,13 +275,13 @@ where } } -impl fmt::Debug for PrivateKeyInfoInner +impl fmt::Debug for PrivateKeyInfo where Params: fmt::Debug, PubKey: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PrivateKeyInfoInner") + f.debug_struct("PrivateKeyInfo") .field("version", &self.version()) .field("algorithm", &self.algorithm) .field("public_key", &self.public_key) @@ -290,7 +290,7 @@ where } #[cfg(feature = "alloc")] -impl<'a, Params, Key, PubKey> TryFrom> for SecretDocument +impl<'a, Params, Key, PubKey> TryFrom> for SecretDocument where Params: der::Choice<'a, Error = der::Error> + Encode, Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, @@ -300,13 +300,13 @@ where { type Error = Error; - fn try_from(private_key: PrivateKeyInfoInner) -> Result { + fn try_from(private_key: PrivateKeyInfo) -> Result { SecretDocument::try_from(&private_key) } } #[cfg(feature = "alloc")] -impl<'a, Params, Key, PubKey> TryFrom<&PrivateKeyInfoInner> for SecretDocument +impl<'a, Params, Key, PubKey> TryFrom<&PrivateKeyInfo> for SecretDocument where Params: der::Choice<'a, Error = der::Error> + Encode, Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, @@ -316,18 +316,18 @@ where { type Error = Error; - fn try_from(private_key: &PrivateKeyInfoInner) -> Result { + fn try_from(private_key: &PrivateKeyInfo) -> Result { Ok(Self::encode_msg(private_key)?) } } #[cfg(feature = "pem")] -impl PemLabel for PrivateKeyInfoInner { +impl PemLabel for PrivateKeyInfo { const PEM_LABEL: &'static str = "PRIVATE KEY"; } #[cfg(feature = "subtle")] -impl ConstantTimeEq for PrivateKeyInfoInner +impl ConstantTimeEq for PrivateKeyInfo where Params: Eq, Key: PartialEq + AsRef<[u8]>, @@ -344,7 +344,7 @@ where } #[cfg(feature = "subtle")] -impl Eq for PrivateKeyInfoInner +impl Eq for PrivateKeyInfo where Params: Eq, Key: AsRef<[u8]> + Eq, @@ -353,7 +353,7 @@ where } #[cfg(feature = "subtle")] -impl PartialEq for PrivateKeyInfoInner +impl PartialEq for PrivateKeyInfo where Params: Eq, Key: PartialEq + AsRef<[u8]>, @@ -364,12 +364,12 @@ where } } -/// [`PrivateKeyInfoInner`] with [`AnyRef`] algorithm parameters, and `&[u8]` key. -pub type PrivateKeyInfo<'a> = PrivateKeyInfoInner, OctetStringRef<'a>, BitStringRef<'a>>; +/// [`PrivateKeyInfo`] with [`AnyRef`] algorithm parameters, and `&[u8]` key. +pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, OctetStringRef<'a>, BitStringRef<'a>>; /// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and `Box<[u8]>` key. #[cfg(feature = "alloc")] -pub type PrivateKeyInfoOwned = PrivateKeyInfoInner; +pub type PrivateKeyInfoOwned = PrivateKeyInfo; /// [`BitStringLike`] marks object that will act like a BitString. /// @@ -395,7 +395,7 @@ mod allocating { } } - impl<'a> RefToOwned<'a> for PrivateKeyInfo<'a> { + impl<'a> RefToOwned<'a> for PrivateKeyInfoRef<'a> { type Owned = PrivateKeyInfoOwned; fn ref_to_owned(&self) -> Self::Owned { PrivateKeyInfoOwned { @@ -407,9 +407,9 @@ mod allocating { } impl OwnedToRef for PrivateKeyInfoOwned { - type Borrowed<'a> = PrivateKeyInfo<'a>; + type Borrowed<'a> = PrivateKeyInfoRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { - PrivateKeyInfo { + PrivateKeyInfoRef { algorithm: self.algorithm.owned_to_ref(), private_key: self.private_key.owned_to_ref(), public_key: self.public_key.owned_to_ref(), diff --git a/pkcs8/src/traits.rs b/pkcs8/src/traits.rs index 9b5b029dc..6d110b6e6 100644 --- a/pkcs8/src/traits.rs +++ b/pkcs8/src/traits.rs @@ -1,6 +1,6 @@ //! Traits for parsing objects from PKCS#8 encoded documents -use crate::{Error, PrivateKeyInfo, Result}; +use crate::{Error, PrivateKeyInfoRef, Result}; #[cfg(feature = "alloc")] use der::SecretDocument; @@ -46,7 +46,7 @@ pub trait DecodePrivateKey: Sized { fn from_pkcs8_pem(s: &str) -> Result { // Validate PEM label let label = pem::decode_label(s.as_bytes())?; - PrivateKeyInfo::validate_pem_label(label)?; + PrivateKeyInfoRef::validate_pem_label(label)?; let doc = SecretDocument::from_pem(s)?.1; Self::from_pkcs8_der(doc.as_bytes()) @@ -78,17 +78,17 @@ pub trait DecodePrivateKey: Sized { #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs8_pem_file(path: impl AsRef) -> Result { let (label, doc) = SecretDocument::read_pem_file(path)?; - PrivateKeyInfo::validate_pem_label(&label)?; + PrivateKeyInfoRef::validate_pem_label(&label)?; Self::from_pkcs8_der(doc.as_bytes()) } } impl DecodePrivateKey for T where - T: for<'a> TryFrom, Error = Error>, + T: for<'a> TryFrom, Error = Error>, { fn from_pkcs8_der(bytes: &[u8]) -> Result { - Self::try_from(PrivateKeyInfo::try_from(bytes)?) + Self::try_from(PrivateKeyInfoRef::try_from(bytes)?) } } @@ -113,7 +113,7 @@ pub trait EncodePrivateKey { #[cfg(feature = "pem")] fn to_pkcs8_pem(&self, line_ending: LineEnding) -> Result> { let doc = self.to_pkcs8_der()?; - Ok(doc.to_pem(PrivateKeyInfo::PEM_LABEL, line_ending)?) + Ok(doc.to_pem(PrivateKeyInfoRef::PEM_LABEL, line_ending)?) } /// Serialize this private key as an encrypted PEM-encoded PKCS#8 private @@ -139,6 +139,6 @@ pub trait EncodePrivateKey { #[cfg(all(feature = "pem", feature = "std"))] fn write_pkcs8_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs8_der()?; - Ok(doc.write_pem_file(path, PrivateKeyInfo::PEM_LABEL, line_ending)?) + Ok(doc.write_pem_file(path, PrivateKeyInfoRef::PEM_LABEL, line_ending)?) } } diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index 8d6541b9e..859eec735 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -3,7 +3,7 @@ #![cfg(feature = "pkcs5")] use hex_literal::hex; -use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfoRef, PrivateKeyInfo}; +use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfoRef, PrivateKeyInfoRef}; #[cfg(feature = "alloc")] use der::Encode; @@ -203,7 +203,7 @@ fn encrypt_ed25519_der_encpriv_aes128_gcm_scrypt() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(scrypt_params, PASSWORD) .unwrap(); @@ -233,7 +233,7 @@ fn encrypt_ed25519_der_encpriv_aes256_gcm_scrypt() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(scrypt_params, PASSWORD) .unwrap(); @@ -254,7 +254,7 @@ fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(pbes2_params, PASSWORD) .unwrap(); @@ -275,7 +275,7 @@ fn encrypt_ed25519_der_encpriv_aes256_scrypt() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(scrypt_params, PASSWORD) .unwrap(); diff --git a/pkcs8/tests/private_key.rs b/pkcs8/tests/private_key.rs index 002112c2d..5bb4ce605 100644 --- a/pkcs8/tests/private_key.rs +++ b/pkcs8/tests/private_key.rs @@ -2,7 +2,7 @@ use der::asn1::{ObjectIdentifier, OctetStringRef}; use hex_literal::hex; -use pkcs8::{PrivateKeyInfo, Version}; +use pkcs8::{PrivateKeyInfoRef, Version}; #[cfg(feature = "alloc")] use der::Encode; @@ -49,7 +49,7 @@ const X25519_PEM_EXAMPLE: &str = include_str!("examples/x25519-priv.pem"); #[test] fn decode_ec_p256_der() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.2.840.10045.2.1".parse().unwrap()); @@ -70,7 +70,7 @@ fn decode_ec_p256_der() { #[test] fn decode_ec_bignp256_der() { - let pk = PrivateKeyInfo::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!( pk.algorithm.oid, @@ -101,7 +101,7 @@ fn decode_ec_bignp256_der() { // https://datatracker.ietf.org/doc/html/rfc8410#section-10.3 #[test] fn decode_ed25519_der_v1() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -125,7 +125,7 @@ fn decode_ed25519_der_v2() { const PUB_KEY: [u8; 32] = hex!("19BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1"); - let pk = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V2); assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -135,7 +135,7 @@ fn decode_ed25519_der_v2() { #[test] fn decode_rsa_2048_der() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.2.840.113549.1.1.1".parse().unwrap()); assert!(pk.algorithm.parameters.unwrap().is_null()); @@ -147,7 +147,7 @@ fn decode_rsa_2048_der() { #[test] fn decode_x25519_der() { - let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(X25519_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.3.101.110".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -163,7 +163,7 @@ fn decode_x25519_der() { #[test] #[cfg(feature = "alloc")] fn encode_ec_p256_der() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); let pk_encoded = pk.to_der().unwrap(); assert_eq!(EC_P256_DER_EXAMPLE, pk_encoded); } @@ -171,7 +171,7 @@ fn encode_ec_p256_der() { #[test] #[cfg(feature = "alloc")] fn encode_ec_bignp256_der() { - let pk = PrivateKeyInfo::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); let pk_encoded = pk.to_der().unwrap(); assert_eq!(EC_BIGN_P256_DER_EXAMPLE, pk_encoded); } @@ -179,59 +179,59 @@ fn encode_ec_bignp256_der() { #[test] #[cfg(feature = "alloc")] fn encode_ed25519_der_v1() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(ED25519_DER_V1_EXAMPLE, pk.to_der().unwrap()); } #[test] #[cfg(all(feature = "alloc", feature = "subtle"))] fn encode_ed25519_der_v2() { - let private_key = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + let private_key = PrivateKeyInfoRef::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); let private_der = private_key.to_der().unwrap(); assert_eq!( private_key, - PrivateKeyInfo::try_from(private_der.as_ref()).unwrap() + PrivateKeyInfoRef::try_from(private_der.as_ref()).unwrap() ); } #[test] #[cfg(feature = "alloc")] fn encode_rsa_2048_der() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(RSA_2048_DER_EXAMPLE, &pk.to_der().unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_ec_p256_pem() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); assert_eq!(EC_P256_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_ec_bignp256_pem() { - let pk = PrivateKeyInfo::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); assert_eq!(EC_BIGN_P256_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_ed25519_pem() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(ED25519_PEM_V1_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_rsa_2048_pem() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(RSA_2048_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_x25519_pem() { - let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(X25519_DER_EXAMPLE).unwrap(); assert_eq!(X25519_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } diff --git a/pkcs8/tests/traits.rs b/pkcs8/tests/traits.rs index 4a603bb94..c9e63d124 100644 --- a/pkcs8/tests/traits.rs +++ b/pkcs8/tests/traits.rs @@ -3,7 +3,7 @@ #![cfg(any(feature = "pem", feature = "std"))] use der::Encode; -use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfo, Result, SecretDocument}; +use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfoRef, Result, SecretDocument}; #[cfg(feature = "pem")] use pkcs8::der::pem::LineEnding; @@ -14,7 +14,7 @@ use tempfile::tempdir; #[cfg(all(feature = "pem", feature = "std"))] use std::fs; -/// Ed25519 `PrivateKeyInfo` encoded as ASN.1 DER +/// Ed25519 `PrivateKeyInfoRef` encoded as ASN.1 DER const ED25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); /// Ed25519 private key encoded as PEM @@ -36,10 +36,10 @@ impl EncodePrivateKey for MockKey { } } -impl TryFrom> for MockKey { +impl TryFrom> for MockKey { type Error = Error; - fn try_from(pkcs8: PrivateKeyInfo<'_>) -> Result { + fn try_from(pkcs8: PrivateKeyInfoRef<'_>) -> Result { Ok(MockKey(pkcs8.to_der()?)) } } From b977b5630b436aba8fb67f5b313a531438cd2616 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 07:53:34 +0000 Subject: [PATCH 08/14] pkcs1: adopt pkcs8 API changes --- pkcs1/src/private_key.rs | 12 ++++++++++-- pkcs1/src/traits.rs | 11 ++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/pkcs1/src/private_key.rs b/pkcs1/src/private_key.rs index d7a7bb554..e26afd66f 100644 --- a/pkcs1/src/private_key.rs +++ b/pkcs1/src/private_key.rs @@ -6,8 +6,8 @@ pub(crate) mod other_prime_info; use crate::{Error, Result, RsaPublicKey, Version}; use core::fmt; use der::{ - asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, - Writer, + asn1::{OctetStringRef, UintRef}, + Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer, }; #[cfg(feature = "alloc")] @@ -172,6 +172,14 @@ impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> { } } +impl<'a> TryFrom> for RsaPrivateKey<'a> { + type Error = Error; + + fn try_from(bytes: OctetStringRef<'a>) -> Result { + Ok(Self::from_der(bytes.as_bytes())?) + } +} + impl fmt::Debug for RsaPrivateKey<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RsaPrivateKey") diff --git a/pkcs1/src/traits.rs b/pkcs1/src/traits.rs index 9276e0b04..9f941310c 100644 --- a/pkcs1/src/traits.rs +++ b/pkcs1/src/traits.rs @@ -15,7 +15,7 @@ use { #[cfg(feature = "pkcs8")] use { crate::{ALGORITHM_ID, ALGORITHM_OID}, - der::asn1::BitStringRef, + der::asn1::{BitStringRef, OctetStringRef}, }; #[cfg(feature = "std")] @@ -157,10 +157,11 @@ pub trait EncodeRsaPublicKey { #[cfg(feature = "pkcs8")] impl DecodeRsaPrivateKey for T where - T: for<'a> TryFrom, Error = pkcs8::Error>, + T: for<'a> TryFrom, Error = pkcs8::Error>, { fn from_pkcs1_der(private_key: &[u8]) -> Result { - Ok(Self::try_from(pkcs8::PrivateKeyInfo { + let private_key = OctetStringRef::new(private_key)?; + Ok(Self::try_from(pkcs8::PrivateKeyInfoRef { algorithm: ALGORITHM_ID, private_key, public_key: None, @@ -185,9 +186,9 @@ where impl EncodeRsaPrivateKey for T { fn to_pkcs1_der(&self) -> Result { let pkcs8_doc = self.to_pkcs8_der()?; - let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(pkcs8_doc.as_bytes())?; + let pkcs8_key = pkcs8::PrivateKeyInfoRef::from_der(pkcs8_doc.as_bytes())?; pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; - RsaPrivateKey::from_der(pkcs8_key.private_key)?.try_into() + RsaPrivateKey::from_der(pkcs8_key.private_key.as_bytes())?.try_into() } } From 9d8dd7dd26a92675e189c0b74ba42112c9312dcf Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 07:53:55 +0000 Subject: [PATCH 09/14] sec1: adopt pkcs8 API changes --- sec1/src/traits.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sec1/src/traits.rs b/sec1/src/traits.rs index ce72ad3b5..212a33269 100644 --- a/sec1/src/traits.rs +++ b/sec1/src/traits.rs @@ -11,7 +11,7 @@ use {crate::LineEnding, alloc::string::String, der::pem::PemLabel}; #[cfg(feature = "pkcs8")] use { crate::{EcPrivateKey, ALGORITHM_OID}, - der::Decode, + der::{asn1::OctetStringRef, Decode}, }; #[cfg(feature = "std")] @@ -88,7 +88,7 @@ pub trait EncodeEcPrivateKey { #[cfg(feature = "pkcs8")] impl DecodeEcPrivateKey for T where - T: for<'a> TryFrom, Error = pkcs8::Error>, + T: for<'a> TryFrom, Error = pkcs8::Error>, { fn from_sec1_der(private_key: &[u8]) -> Result { let params_oid = EcPrivateKey::from_der(private_key)? @@ -100,7 +100,9 @@ where parameters: params_oid.as_ref().map(Into::into), }; - Ok(Self::try_from(pkcs8::PrivateKeyInfo { + let private_key = OctetStringRef::new(private_key)?; + + Ok(Self::try_from(pkcs8::PrivateKeyInfoRef { algorithm, private_key, public_key: None, @@ -112,10 +114,10 @@ where impl EncodeEcPrivateKey for T { fn to_sec1_der(&self) -> Result { let doc = self.to_pkcs8_der()?; - let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(doc.as_bytes())?; + let pkcs8_key = pkcs8::PrivateKeyInfoRef::from_der(doc.as_bytes())?; pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; - let mut pkcs1_key = EcPrivateKey::from_der(pkcs8_key.private_key)?; + let mut pkcs1_key = EcPrivateKey::from_der(pkcs8_key.private_key.as_bytes())?; pkcs1_key.parameters = Some(pkcs8_key.algorithm.parameters_oid()?.into()); pkcs1_key.try_into() } From 56a0fbd3d96bb59fea4d54622eaa2818b4d57377 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 17:30:12 +0000 Subject: [PATCH 10/14] cms: loosen pkcs5 dependency Signed-off-by: Arthur Gautier --- cms/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/Cargo.toml b/cms/Cargo.toml index 1d1be5ba0..eed22cb25 100644 --- a/cms/Cargo.toml +++ b/cms/Cargo.toml @@ -35,7 +35,7 @@ zeroize = { version = "1.8.1", optional = true } getrandom = "0.2" hex-literal = "0.4" pem-rfc7468 = "1.0.0-rc.1" -pkcs5 = "=0.8.0-rc.0" +pkcs5 = "0.8.0-rc.1" rand = "0.8.5" rsa = { version = "=0.10.0-pre.2", features = ["sha2"] } ecdsa = { version = "=0.17.0-pre.7", features = ["digest", "pem"] } From d0a7984a832bc43741d83a4807def0a535aabf04 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 17:30:59 +0000 Subject: [PATCH 11/14] use git dependencies for CI Signed-off-by: Arthur Gautier --- Cargo.lock | 26 +++++++------------------- Cargo.toml | 7 ++++++- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70e3ed8ad..5dae22193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -387,7 +387,7 @@ dependencies = [ "hex-literal", "p256", "pem-rfc7468", - "pkcs5 0.8.0-rc.0", + "pkcs5", "rand", "rsa", "sha1", @@ -569,7 +569,7 @@ dependencies = [ [[package]] name = "ecdsa" version = "0.17.0-pre.7" -source = "git+https://github.com/RustCrypto/signatures#cf34cd2ffdbf5579b3fa2d1a5361464484e86ee3" +source = "git+https://github.com/baloo/signatures?branch=baloo/pkcs8/api-change#2ec8160db97f1cdbd656e6b411683011f5d0f3bf" dependencies = [ "der", "digest", @@ -588,8 +588,7 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[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#df6f7ab4b577adcc68e0a5a1a50f0d17b3dfc949" dependencies = [ "base16ct", "crypto-bigint", @@ -1081,7 +1080,7 @@ dependencies = [ "der", "digest", "hex-literal", - "pkcs5 0.8.0-rc.1", + "pkcs5", "pkcs8", "sha2", "spki", @@ -1090,16 +1089,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "pkcs5" -version = "0.8.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f7844403c0bf02e9a4a3fbb8015f1f6f2f1eb221ffaafd4a8bfdc7143c05e3" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkcs5" version = "0.8.0-rc.1" @@ -1124,7 +1113,7 @@ version = "0.11.0-rc.0" dependencies = [ "der", "hex-literal", - "pkcs5 0.8.0-rc.1", + "pkcs5", "rand_core", "spki", "subtle", @@ -1303,7 +1292,7 @@ checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca" [[package]] name = "rfc6979" version = "0.5.0-pre.4" -source = "git+https://github.com/RustCrypto/signatures#cf34cd2ffdbf5579b3fa2d1a5361464484e86ee3" +source = "git+https://github.com/baloo/signatures?branch=baloo/pkcs8/api-change#2ec8160db97f1cdbd656e6b411683011f5d0f3bf" dependencies = [ "hmac", "subtle", @@ -1334,8 +1323,7 @@ dependencies = [ [[package]] name = "rsa" version = "0.10.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e864e43f5d003321ab452feea6450f9611d7be6726489b4ec051da34774c62" +source = "git+https://github.com/baloo/RSA?branch=baloo/pkcs8/api-changes#40113d8f924edc984a78449f244c6b47659bdc65" dependencies = [ "const-oid", "digest", diff --git a/Cargo.toml b/Cargo.toml index a59a9dcb6..b496c0903 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,4 +60,9 @@ x509-cert = { path = "./x509-cert" } x509-ocsp = { path = "./x509-ocsp" } # Temp patches to external crates -ecdsa = { git = "https://github.com/RustCrypto/signatures" } +# https://github.com/RustCrypto/signatures/pull/851 +ecdsa = { git = "https://github.com/baloo/signatures", branch = "baloo/pkcs8/api-change" } +# https://github.com/RustCrypto/RSA/pull/446 +rsa = { git = "https://github.com/baloo/RSA", branch = "baloo/pkcs8/api-changes" } +# https://github.com/RustCrypto/traits/pull/1650 +elliptic-curve = { git = "https://github.com/baloo/traits.git", branch ="baloo/elliptic-curve/pkcs8-API-break" } From a1448d6dcc4494f2a72ea39fd917716da892ace7 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 18:09:42 +0000 Subject: [PATCH 12/14] pkcs8: EncryptedPrivateKeyInfo use OctetString Signed-off-by: Arthur Gautier --- pkcs8/src/encrypted_private_key_info.rs | 37 +++++++++++++------------ pkcs8/tests/encrypted_private_key.rs | 9 ++++-- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs index b3febeca9..9e4ec471f 100644 --- a/pkcs8/src/encrypted_private_key_info.rs +++ b/pkcs8/src/encrypted_private_key_info.rs @@ -3,13 +3,13 @@ use crate::{Error, Result}; use core::fmt; use der::{ - asn1::OctetStringRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, - Sequence, Writer, + asn1::OctetStringRef, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, + Reader, Sequence, Writer, }; use pkcs5::EncryptionScheme; #[cfg(feature = "alloc")] -use {alloc::boxed::Box, der::SecretDocument}; +use der::{asn1::OctetString, SecretDocument}; #[cfg(feature = "encryption")] use {pkcs5::pbes2, rand_core::CryptoRngCore}; @@ -48,7 +48,8 @@ pub struct EncryptedPrivateKeyInfo { impl<'a, Data> EncryptedPrivateKeyInfo where - Data: AsRef<[u8]> + From<&'a [u8]>, + Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a, + Data: AsRef<[u8]>, { /// Attempt to decrypt this encrypted private key using the provided /// password to derive an encryption key. @@ -81,6 +82,7 @@ where doc: &[u8], ) -> Result { let encrypted_data = pbes2_params.encrypt(password, doc)?; + let encrypted_data = OctetStringRef::new(&encrypted_data)?; EncryptedPrivateKeyInfo { encryption_algorithm: pbes2_params.into(), @@ -92,7 +94,7 @@ where impl<'a, Data> DecodeValue<'a> for EncryptedPrivateKeyInfo where - Data: From<&'a [u8]>, + Data: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, { type Error = der::Error; @@ -100,7 +102,7 @@ where reader.read_nested(header.length, |reader| { Ok(Self { encryption_algorithm: reader.decode()?, - encrypted_data: OctetStringRef::decode(reader)?.as_bytes().into(), + encrypted_data: reader.decode()?, }) }) } @@ -108,28 +110,27 @@ where impl EncodeValue for EncryptedPrivateKeyInfo where - Data: AsRef<[u8]>, + Data: EncodeValue + FixedTag, { fn value_len(&self) -> der::Result { - self.encryption_algorithm.encoded_len()? - + OctetStringRef::new(self.encrypted_data.as_ref())?.encoded_len()? + self.encryption_algorithm.encoded_len()? + self.encrypted_data.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.encryption_algorithm.encode(writer)?; - OctetStringRef::new(self.encrypted_data.as_ref())?.encode(writer)?; + self.encrypted_data.encode(writer)?; Ok(()) } } impl<'a, Data> Sequence<'a> for EncryptedPrivateKeyInfo where - Data: AsRef<[u8]> + From<&'a [u8]> + Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a { } impl<'a, Data> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo where - Data: AsRef<[u8]> + From<&'a [u8]> + 'a, + Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a, { type Error = Error; @@ -149,7 +150,7 @@ impl fmt::Debug for EncryptedPrivateKeyInfo { #[cfg(feature = "alloc")] impl<'a, Data> TryFrom> for SecretDocument where - Data: AsRef<[u8]> + From<&'a [u8]>, + Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a, { type Error = Error; @@ -161,7 +162,7 @@ where #[cfg(feature = "alloc")] impl<'a, Data> TryFrom<&EncryptedPrivateKeyInfo> for SecretDocument where - Data: AsRef<[u8]> + From<&'a [u8]>, + Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a, { type Error = Error; @@ -175,9 +176,9 @@ impl PemLabel for EncryptedPrivateKeyInfo { const PEM_LABEL: &'static str = "ENCRYPTED PRIVATE KEY"; } -/// [`EncryptedPrivateKeyInfo`] with `&[u8]` encrypted data. -pub type EncryptedPrivateKeyInfoRef<'a> = EncryptedPrivateKeyInfo<&'a [u8]>; +/// [`EncryptedPrivateKeyInfo`] with [`OctetStringRef`] encrypted data. +pub type EncryptedPrivateKeyInfoRef<'a> = EncryptedPrivateKeyInfo>; #[cfg(feature = "alloc")] -/// [`EncryptedPrivateKeyInfo`] with `Box<[u8]>` encrypted data. -pub type EncryptedPrivateKeyInfoOwned = EncryptedPrivateKeyInfo>; +/// [`EncryptedPrivateKeyInfo`] with [`OctetString`] encrypted data. +pub type EncryptedPrivateKeyInfoOwned = EncryptedPrivateKeyInfo; diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index 859eec735..a1560d37c 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -2,6 +2,7 @@ #![cfg(feature = "pkcs5")] +use der::asn1::OctetStringRef; use hex_literal::hex; use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfoRef, PrivateKeyInfoRef}; @@ -130,7 +131,9 @@ fn decode_ed25519_encpriv_aes128_pbkdf2_sha1_der() { // $ openssl asn1parse -inform der -in tests/examples/ed25519-encpriv-aes128-sha1.der assert_eq!( pk.encrypted_data, - &hex!("4B4D091548EAC381EE7663B21234CD4FF3C9DF664D713394CACCEA7C9B982BD8F29910FABCA4BF7BE0431FAC5C4D657BE997C1F5BF40E2DA465AC1FCC2E30470") + OctetStringRef::new( + &hex!("4B4D091548EAC381EE7663B21234CD4FF3C9DF664D713394CACCEA7C9B982BD8F29910FABCA4BF7BE0431FAC5C4D657BE997C1F5BF40E2DA465AC1FCC2E30470") + ).unwrap() ); } @@ -163,7 +166,9 @@ fn decode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { // $ openssl asn1parse -inform der -in tests/examples/ed25519-encpriv-aes256-sha256.der assert_eq!( pk.encrypted_data, - &hex!("D0CD6C770F4BB87176422305C17401809E226674CE74185D221BFDAA95069890C8882FCE02B05D41BCBF54B035595BCD4154B32593708469B86AACF8815A7B2B") + OctetStringRef::new( + &hex!("D0CD6C770F4BB87176422305C17401809E226674CE74185D221BFDAA95069890C8882FCE02B05D41BCBF54B035595BCD4154B32593708469B86AACF8815A7B2B") + ).unwrap() ); } From b9a1d15fa7891da448c81cebbbaf6a758b9881e9 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 18:10:48 +0000 Subject: [PATCH 13/14] pkcs8: only pem brings `alloc` Signed-off-by: Arthur Gautier --- pkcs8/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index 734a2dd21..adcd91ce6 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -70,7 +70,7 @@ //! [PKCS#5v2 Password Based Encryption Scheme 2 (RFC 8018)]: https://tools.ietf.org/html/rfc8018#section-6.2 //! [scrypt]: https://en.wikipedia.org/wiki/Scrypt -#[cfg(feature = "alloc")] +#[cfg(feature = "pem")] extern crate alloc; #[cfg(feature = "std")] extern crate std; From 3400a03496107f2e86d0f541976b454d9e45857d Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 19 Aug 2024 18:13:54 +0000 Subject: [PATCH 14/14] pkcs12: move to `EncryptedPrivateKeyInfoRef` Signed-off-by: Arthur Gautier --- pkcs12/tests/cert_tests.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkcs12/tests/cert_tests.rs b/pkcs12/tests/cert_tests.rs index defa936ce..c25f8d390 100644 --- a/pkcs12/tests/cert_tests.rs +++ b/pkcs12/tests/cert_tests.rs @@ -13,7 +13,7 @@ use pkcs8::{ self, pbes2::{AES_256_CBC_OID, HMAC_WITH_SHA256_OID, PBES2_OID, PBKDF2_OID}, }, - EncryptedPrivateKeyInfo, + EncryptedPrivateKeyInfoRef, }; use spki::AlgorithmIdentifierOwned; @@ -242,9 +242,9 @@ fn decode_sample_pfx() { for safe_bag in safe_bags { match safe_bag.bag_id { pkcs12::PKCS_12_PKCS8_KEY_BAG_OID => { - let cs: ContextSpecific = + let cs: ContextSpecific> = ContextSpecific::from_der(&safe_bag.bag_value).unwrap(); - let mut ciphertext = cs.value.encrypted_data.to_vec(); + let mut ciphertext = cs.value.encrypted_data.as_bytes().to_vec(); let plaintext = cs .value .encryption_algorithm @@ -628,9 +628,9 @@ fn decode_sample_pfx2() { for safe_bag in safe_bags { match safe_bag.bag_id { pkcs12::PKCS_12_PKCS8_KEY_BAG_OID => { - let cs: ContextSpecific = + let cs: ContextSpecific> = ContextSpecific::from_der(&safe_bag.bag_value).unwrap(); - let mut ciphertext = cs.value.encrypted_data.to_vec(); + let mut ciphertext = cs.value.encrypted_data.as_bytes().to_vec(); let plaintext = cs .value .encryption_algorithm