From 057cee0ac28cb9efc59b813c3ba843d6e57bd3fc Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 8 Aug 2023 19:20:21 -0600 Subject: [PATCH 01/11] [WIP] pkcs5: remove lifetimes Removes lifetimes from all types in the `pkcs5` crate, making them own their data. --- pkcs5/src/lib.rs | 42 ++++++------- pkcs5/src/pbes2.rs | 90 ++++++++++++++-------------- pkcs5/src/pbes2/encryption.rs | 40 ++++++------- pkcs5/src/pbes2/kdf.rs | 107 ++++++++++++++++++---------------- pkcs5/src/pbes2/kdf/salt.rs | 102 ++++++++++++++++++++++++++++++++ pkcs5/tests/pbes2.rs | 20 +++---- 6 files changed, 252 insertions(+), 149 deletions(-) create mode 100644 pkcs5/src/pbes2/kdf/salt.rs diff --git a/pkcs5/src/lib.rs b/pkcs5/src/lib.rs index 08993c245..f8439ad90 100644 --- a/pkcs5/src/lib.rs +++ b/pkcs5/src/lib.rs @@ -49,7 +49,7 @@ use alloc::vec::Vec; #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] #[allow(clippy::large_enum_variant)] -pub enum EncryptionScheme<'a> { +pub enum EncryptionScheme { /// Password-Based Encryption Scheme 1 as defined in [RFC 8018 Section 6.1]. /// /// [RFC 8018 Section 6.1]: https://tools.ietf.org/html/rfc8018#section-6.1 @@ -58,10 +58,10 @@ pub enum EncryptionScheme<'a> { /// Password-Based Encryption Scheme 2 as defined in [RFC 8018 Section 6.2]. /// /// [RFC 8018 Section 6.2]: https://tools.ietf.org/html/rfc8018#section-6.2 - Pbes2(pbes2::Parameters<'a>), + Pbes2(pbes2::Parameters), } -impl<'a> EncryptionScheme<'a> { +impl EncryptionScheme { /// Attempt to decrypt the given ciphertext, allocating and returning a /// byte vector containing the plaintext. #[cfg(all(feature = "alloc", feature = "pbes2"))] @@ -79,11 +79,11 @@ impl<'a> EncryptionScheme<'a> { /// is unsupported, or if the ciphertext is malformed (e.g. not a multiple /// of a block mode's padding) #[cfg(feature = "pbes2")] - pub fn decrypt_in_place<'b>( + pub fn decrypt_in_place<'a>( &self, password: impl AsRef<[u8]>, - buffer: &'b mut [u8], - ) -> Result<&'b [u8]> { + buffer: &'a mut [u8], + ) -> Result<&'a [u8]> { match self { Self::Pbes2(params) => params.decrypt_in_place(password, buffer), Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport), @@ -103,12 +103,12 @@ impl<'a> EncryptionScheme<'a> { /// Encrypt the given ciphertext in-place using a key derived from the /// provided password and this scheme's parameters. #[cfg(feature = "pbes2")] - pub fn encrypt_in_place<'b>( + pub fn encrypt_in_place<'a>( &self, password: impl AsRef<[u8]>, - buffer: &'b mut [u8], + buffer: &'a mut [u8], pos: usize, - ) -> Result<&'b [u8]> { + ) -> Result<&'a [u8]> { match self { Self::Pbes2(params) => params.encrypt_in_place(password, buffer, pos), Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport), @@ -132,7 +132,7 @@ impl<'a> EncryptionScheme<'a> { } /// Get [`pbes2::Parameters`] if it is the selected algorithm. - pub fn pbes2(&self) -> Option<&pbes2::Parameters<'a>> { + pub fn pbes2(&self) -> Option<&pbes2::Parameters> { match self { Self::Pbes2(params) => Some(params), _ => None, @@ -140,13 +140,13 @@ impl<'a> EncryptionScheme<'a> { } } -impl<'a> DecodeValue<'a> for EncryptionScheme<'a> { +impl<'a> DecodeValue<'a> for EncryptionScheme { fn decode_value>(decoder: &mut R, header: Header) -> der::Result { AlgorithmIdentifierRef::decode_value(decoder, header)?.try_into() } } -impl EncodeValue for EncryptionScheme<'_> { +impl EncodeValue for EncryptionScheme { fn value_len(&self) -> der::Result { match self { Self::Pbes1(pbes1) => pbes1.oid().encoded_len()? + pbes1.parameters.encoded_len()?, @@ -170,24 +170,24 @@ impl EncodeValue for EncryptionScheme<'_> { } } -impl<'a> Sequence<'a> for EncryptionScheme<'a> {} +impl Sequence<'_> for EncryptionScheme {} -impl<'a> From for EncryptionScheme<'a> { - fn from(alg: pbes1::Algorithm) -> EncryptionScheme<'a> { +impl From for EncryptionScheme { + fn from(alg: pbes1::Algorithm) -> EncryptionScheme { Self::Pbes1(alg) } } -impl<'a> From> for EncryptionScheme<'a> { - fn from(params: pbes2::Parameters<'a>) -> EncryptionScheme<'a> { +impl From for EncryptionScheme { + fn from(params: pbes2::Parameters) -> EncryptionScheme { Self::Pbes2(params) } } -impl<'a> TryFrom> for EncryptionScheme<'a> { +impl TryFrom> for EncryptionScheme { type Error = der::Error; - fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result> { + fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result { if alg.oid == pbes2::PBES2_OID { match alg.parameters { Some(params) => pbes2::Parameters::try_from(params).map(Into::into), @@ -199,10 +199,10 @@ impl<'a> TryFrom> for EncryptionScheme<'a> { } } -impl<'a> TryFrom<&'a [u8]> for EncryptionScheme<'a> { +impl TryFrom<&[u8]> for EncryptionScheme { type Error = der::Error; - fn try_from(bytes: &'a [u8]) -> der::Result> { + fn try_from(bytes: &[u8]) -> der::Result { AlgorithmIdentifierRef::from_der(bytes)?.try_into() } } diff --git a/pkcs5/src/pbes2.rs b/pkcs5/src/pbes2.rs index 301105cc2..095ae1ddb 100644 --- a/pkcs5/src/pbes2.rs +++ b/pkcs5/src/pbes2.rs @@ -8,7 +8,7 @@ mod kdf; mod encryption; pub use self::kdf::{ - Kdf, Pbkdf2Params, Pbkdf2Prf, ScryptParams, HMAC_WITH_SHA1_OID, HMAC_WITH_SHA256_OID, + Kdf, Pbkdf2Params, Pbkdf2Prf, Salt, ScryptParams, HMAC_WITH_SHA1_OID, HMAC_WITH_SHA256_OID, PBKDF2_OID, SCRYPT_OID, }; @@ -66,21 +66,21 @@ const DES_BLOCK_SIZE: usize = 8; /// /// [RFC 8018 Appendix A.4]: https://tools.ietf.org/html/rfc8018#appendix-A.4 #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Parameters<'a> { +pub struct Parameters { /// Key derivation function - pub kdf: Kdf<'a>, + pub kdf: Kdf, /// Encryption scheme - pub encryption: EncryptionScheme<'a>, + pub encryption: EncryptionScheme, } -impl<'a> Parameters<'a> { +impl Parameters { /// Initialize PBES2 parameters using PBKDF2-SHA256 as the password-based /// key derivation function and AES-128-CBC as the symmetric cipher. pub fn pbkdf2_sha256_aes128cbc( pbkdf2_iterations: u32, - pbkdf2_salt: &'a [u8], - aes_iv: &'a [u8; AES_BLOCK_SIZE], + pbkdf2_salt: &[u8], + aes_iv: [u8; AES_BLOCK_SIZE], ) -> Result { let kdf = Pbkdf2Params::hmac_with_sha256(pbkdf2_iterations, pbkdf2_salt)?.into(); let encryption = EncryptionScheme::Aes128Cbc { iv: aes_iv }; @@ -91,8 +91,8 @@ impl<'a> Parameters<'a> { /// key derivation function and AES-256-CBC as the symmetric cipher. pub fn pbkdf2_sha256_aes256cbc( pbkdf2_iterations: u32, - pbkdf2_salt: &'a [u8], - aes_iv: &'a [u8; AES_BLOCK_SIZE], + pbkdf2_salt: &[u8], + aes_iv: [u8; AES_BLOCK_SIZE], ) -> Result { let kdf = Pbkdf2Params::hmac_with_sha256(pbkdf2_iterations, pbkdf2_salt)?.into(); let encryption = EncryptionScheme::Aes256Cbc { iv: aes_iv }; @@ -108,8 +108,8 @@ impl<'a> Parameters<'a> { #[cfg(feature = "pbes2")] pub fn scrypt_aes128cbc( params: scrypt::Params, - salt: &'a [u8], - aes_iv: &'a [u8; AES_BLOCK_SIZE], + salt: &[u8], + aes_iv: [u8; AES_BLOCK_SIZE], ) -> Result { let kdf = ScryptParams::from_params_and_salt(params, salt)?.into(); let encryption = EncryptionScheme::Aes128Cbc { iv: aes_iv }; @@ -128,8 +128,8 @@ impl<'a> Parameters<'a> { #[cfg(feature = "pbes2")] pub fn scrypt_aes256cbc( params: scrypt::Params, - salt: &'a [u8], - aes_iv: &'a [u8; AES_BLOCK_SIZE], + salt: &[u8], + aes_iv: [u8; AES_BLOCK_SIZE], ) -> Result { let kdf = ScryptParams::from_params_and_salt(params, salt)?.into(); let encryption = EncryptionScheme::Aes256Cbc { iv: aes_iv }; @@ -153,11 +153,11 @@ impl<'a> Parameters<'a> { /// is unsupported, or if the ciphertext is malformed (e.g. not a multiple /// of a block mode's padding) #[cfg(feature = "pbes2")] - pub fn decrypt_in_place<'b>( + pub fn decrypt_in_place<'a>( &self, password: impl AsRef<[u8]>, - buffer: &'b mut [u8], - ) -> Result<&'b [u8]> { + buffer: &'a mut [u8], + ) -> Result<&'a [u8]> { encryption::decrypt_in_place(self, password, buffer) } @@ -182,23 +182,23 @@ impl<'a> Parameters<'a> { /// provided password and this scheme's parameters, writing the ciphertext /// into the same buffer. #[cfg(feature = "pbes2")] - pub fn encrypt_in_place<'b>( + pub fn encrypt_in_place<'a>( &self, password: impl AsRef<[u8]>, - buffer: &'b mut [u8], + buffer: &'a mut [u8], pos: usize, - ) -> Result<&'b [u8]> { + ) -> Result<&'a [u8]> { encryption::encrypt_in_place(self, password, buffer, pos) } } -impl<'a> DecodeValue<'a> for Parameters<'a> { +impl<'a> DecodeValue<'a> for Parameters { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { AnyRef::decode_value(reader, header)?.try_into() } } -impl EncodeValue for Parameters<'_> { +impl EncodeValue for Parameters { fn value_len(&self) -> der::Result { self.kdf.encoded_len()? + self.encryption.encoded_len()? } @@ -210,12 +210,12 @@ impl EncodeValue for Parameters<'_> { } } -impl<'a> Sequence<'a> for Parameters<'a> {} +impl Sequence<'_> for Parameters {} -impl<'a> TryFrom> for Parameters<'a> { +impl TryFrom> for Parameters { type Error = der::Error; - fn try_from(any: AnyRef<'a>) -> der::Result { + fn try_from(any: AnyRef<'_>) -> der::Result { any.sequence(|params| { let kdf = AlgorithmIdentifierRef::decode(params)?; let encryption = AlgorithmIdentifierRef::decode(params)?; @@ -231,41 +231,41 @@ impl<'a> TryFrom> for Parameters<'a> { /// Symmetric encryption scheme used by PBES2. #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum EncryptionScheme<'a> { +pub enum EncryptionScheme { /// AES-128 in CBC mode Aes128Cbc { /// Initialization vector - iv: &'a [u8; AES_BLOCK_SIZE], + iv: [u8; AES_BLOCK_SIZE], }, /// AES-192 in CBC mode Aes192Cbc { /// Initialization vector - iv: &'a [u8; AES_BLOCK_SIZE], + iv: [u8; AES_BLOCK_SIZE], }, /// AES-256 in CBC mode Aes256Cbc { /// Initialization vector - iv: &'a [u8; AES_BLOCK_SIZE], + iv: [u8; AES_BLOCK_SIZE], }, /// 3-Key Triple DES in CBC mode #[cfg(feature = "3des")] DesEde3Cbc { /// Initialisation vector - iv: &'a [u8; DES_BLOCK_SIZE], + iv: [u8; DES_BLOCK_SIZE], }, /// DES in CBC mode #[cfg(feature = "des-insecure")] DesCbc { /// Initialisation vector - iv: &'a [u8; DES_BLOCK_SIZE], + iv: [u8; DES_BLOCK_SIZE], }, } -impl<'a> EncryptionScheme<'a> { +impl EncryptionScheme { /// Get the size of a key used by this algorithm in bytes. pub fn key_size(&self) -> usize { match self { @@ -300,19 +300,19 @@ impl<'a> EncryptionScheme<'a> { } } -impl<'a> Decode<'a> for EncryptionScheme<'a> { +impl<'a> Decode<'a> for EncryptionScheme { fn decode>(reader: &mut R) -> der::Result { AlgorithmIdentifierRef::decode(reader).and_then(TryInto::try_into) } } -impl<'a> TryFrom> for EncryptionScheme<'a> { +impl TryFrom> for EncryptionScheme { type Error = der::Error; - fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result { + fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result { // TODO(tarcieri): support for non-AES algorithms? let iv = match alg.parameters { - Some(params) => params.decode_as::>()?.as_bytes(), + Some(params) => params.decode_as::>()?.as_bytes(), None => return Err(Tag::OctetString.value_error()), }; @@ -349,18 +349,18 @@ impl<'a> TryFrom> for EncryptionScheme<'a> { } } -impl<'a> TryFrom> for AlgorithmIdentifierRef<'a> { +impl<'a> TryFrom<&'a EncryptionScheme> for AlgorithmIdentifierRef<'a> { type Error = der::Error; - fn try_from(scheme: EncryptionScheme<'a>) -> der::Result { + fn try_from(scheme: &'a EncryptionScheme) -> der::Result { let parameters = OctetStringRef::new(match scheme { - EncryptionScheme::Aes128Cbc { iv } => iv, - EncryptionScheme::Aes192Cbc { iv } => iv, - EncryptionScheme::Aes256Cbc { iv } => iv, + EncryptionScheme::Aes128Cbc { iv } => iv.as_slice(), + EncryptionScheme::Aes192Cbc { iv } => iv.as_slice(), + EncryptionScheme::Aes256Cbc { iv } => iv.as_slice(), #[cfg(feature = "des-insecure")] - EncryptionScheme::DesCbc { iv } => iv, + EncryptionScheme::DesCbc { iv } => iv.as_slice(), #[cfg(feature = "3des")] - EncryptionScheme::DesEde3Cbc { iv } => iv, + EncryptionScheme::DesEde3Cbc { iv } => iv.as_slice(), })?; Ok(AlgorithmIdentifierRef { @@ -370,12 +370,12 @@ impl<'a> TryFrom> for AlgorithmIdentifierRef<'a> { } } -impl<'a> Encode for EncryptionScheme<'a> { +impl Encode for EncryptionScheme { fn encoded_len(&self) -> der::Result { - AlgorithmIdentifierRef::try_from(*self)?.encoded_len() + AlgorithmIdentifierRef::try_from(self)?.encoded_len() } fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { - AlgorithmIdentifierRef::try_from(*self)?.encode(writer) + AlgorithmIdentifierRef::try_from(self)?.encode(writer) } } diff --git a/pkcs5/src/pbes2/encryption.rs b/pkcs5/src/pbes2/encryption.rs index ea029b66a..86349926d 100644 --- a/pkcs5/src/pbes2/encryption.rs +++ b/pkcs5/src/pbes2/encryption.rs @@ -20,7 +20,7 @@ use scrypt::scrypt; const MAX_KEY_LEN: usize = 32; fn cbc_encrypt<'a, C: BlockEncryptMut + BlockCipher + KeyInit>( - es: EncryptionScheme<'_>, + es: EncryptionScheme, key: EncryptionKey, iv: &[u8], buffer: &'a mut [u8], @@ -33,7 +33,7 @@ fn cbc_encrypt<'a, C: BlockEncryptMut + BlockCipher + KeyInit>( } fn cbc_decrypt<'a, C: BlockDecryptMut + BlockCipher + KeyInit>( - es: EncryptionScheme<'_>, + es: EncryptionScheme, key: EncryptionKey, iv: &[u8], buffer: &'a mut [u8], @@ -45,7 +45,7 @@ fn cbc_decrypt<'a, C: BlockDecryptMut + BlockCipher + KeyInit>( } pub fn encrypt_in_place<'b>( - params: &Parameters<'_>, + params: &Parameters, password: impl AsRef<[u8]>, buf: &'b mut [u8], pos: usize, @@ -58,11 +58,11 @@ pub fn encrypt_in_place<'b>( let key = EncryptionKey::derive_from_password(password.as_ref(), ¶ms.kdf, key_size)?; match es { - EncryptionScheme::Aes128Cbc { iv } => cbc_encrypt::(es, key, iv, buf, pos), - EncryptionScheme::Aes192Cbc { iv } => cbc_encrypt::(es, key, iv, buf, pos), - EncryptionScheme::Aes256Cbc { iv } => cbc_encrypt::(es, key, iv, buf, pos), + EncryptionScheme::Aes128Cbc { iv } => cbc_encrypt::(es, key, &iv, buf, pos), + EncryptionScheme::Aes192Cbc { iv } => cbc_encrypt::(es, key, &iv, buf, pos), + EncryptionScheme::Aes256Cbc { iv } => cbc_encrypt::(es, key, &iv, buf, pos), #[cfg(feature = "3des")] - EncryptionScheme::DesEde3Cbc { iv } => cbc_encrypt::(es, key, iv, buf, pos), + EncryptionScheme::DesEde3Cbc { iv } => cbc_encrypt::(es, key, &iv, buf, pos), #[cfg(feature = "des-insecure")] EncryptionScheme::DesCbc { .. } => Err(Error::UnsupportedAlgorithm { oid: super::DES_CBC_OID, @@ -72,7 +72,7 @@ pub fn encrypt_in_place<'b>( /// Decrypt a message encrypted with PBES2-based key derivation pub fn decrypt_in_place<'a>( - params: &Parameters<'_>, + params: &Parameters, password: impl AsRef<[u8]>, buf: &'a mut [u8], ) -> Result<&'a [u8]> { @@ -80,13 +80,13 @@ pub fn decrypt_in_place<'a>( let key = EncryptionKey::derive_from_password(password.as_ref(), ¶ms.kdf, es.key_size())?; match es { - EncryptionScheme::Aes128Cbc { iv } => cbc_decrypt::(es, key, iv, buf), - EncryptionScheme::Aes192Cbc { iv } => cbc_decrypt::(es, key, iv, buf), - EncryptionScheme::Aes256Cbc { iv } => cbc_decrypt::(es, key, iv, buf), + EncryptionScheme::Aes128Cbc { iv } => cbc_decrypt::(es, key, &iv, buf), + EncryptionScheme::Aes192Cbc { iv } => cbc_decrypt::(es, key, &iv, buf), + EncryptionScheme::Aes256Cbc { iv } => cbc_decrypt::(es, key, &iv, buf), #[cfg(feature = "3des")] - EncryptionScheme::DesEde3Cbc { iv } => cbc_decrypt::(es, key, iv, buf), + EncryptionScheme::DesEde3Cbc { iv } => cbc_decrypt::(es, key, &iv, buf), #[cfg(feature = "des-insecure")] - EncryptionScheme::DesCbc { iv } => cbc_decrypt::(es, key, iv, buf), + EncryptionScheme::DesCbc { iv } => cbc_decrypt::(es, key, &iv, buf), } } @@ -99,7 +99,7 @@ struct EncryptionKey { impl EncryptionKey { /// Derive an encryption key using the supplied PBKDF parameters. - pub fn derive_from_password(password: &[u8], kdf: &Kdf<'_>, key_size: usize) -> Result { + pub fn derive_from_password(password: &[u8], kdf: &Kdf, key_size: usize) -> Result { // if the kdf params defined a key length, ensure it matches the required key size if let Some(len) = kdf.key_length() { if key_size != len.into() { @@ -153,7 +153,7 @@ impl EncryptionKey { } /// Derive key using PBKDF2. - fn derive_with_pbkdf2(password: &[u8], params: &Pbkdf2Params<'_>, length: usize) -> Self + fn derive_with_pbkdf2(password: &[u8], params: &Pbkdf2Params, length: usize) -> Self where D: CoreProxy, D::Core: Sync @@ -170,7 +170,7 @@ impl EncryptionKey { pbkdf2_hmac::( password, - params.salt, + params.salt.as_ref(), params.iteration_count, &mut buffer[..length], ); @@ -179,15 +179,11 @@ impl EncryptionKey { } /// Derive key using scrypt. - fn derive_with_scrypt( - password: &[u8], - params: &ScryptParams<'_>, - length: usize, - ) -> Result { + fn derive_with_scrypt(password: &[u8], params: &ScryptParams, length: usize) -> Result { let mut buffer = [0u8; MAX_KEY_LEN]; scrypt( password, - params.salt, + params.salt.as_ref(), ¶ms.try_into()?, &mut buffer[..length], ) diff --git a/pkcs5/src/pbes2/kdf.rs b/pkcs5/src/pbes2/kdf.rs index 63378cbcb..b16496351 100644 --- a/pkcs5/src/pbes2/kdf.rs +++ b/pkcs5/src/pbes2/kdf.rs @@ -1,8 +1,12 @@ //! Key derivation functions. +mod salt; + +pub use self::salt::Salt; + use crate::{AlgorithmIdentifierRef, Error, Result}; use der::{ - asn1::{AnyRef, ObjectIdentifier, OctetStringRef}, + asn1::{AnyRef, ObjectIdentifier}, Decode, DecodeValue, Encode, EncodeValue, ErrorKind, Length, Reader, Sequence, Tag, Tagged, Writer, }; @@ -40,15 +44,15 @@ type ScryptCost = u64; /// Password-based key derivation function. #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum Kdf<'a> { +pub enum Kdf { /// Password-Based Key Derivation Function 2 (PBKDF2). - Pbkdf2(Pbkdf2Params<'a>), + Pbkdf2(Pbkdf2Params), /// scrypt sequential memory-hard password hashing function. - Scrypt(ScryptParams<'a>), + Scrypt(ScryptParams), } -impl<'a> Kdf<'a> { +impl Kdf { /// Get derived key length in bytes, if defined. // TODO(tarcieri): rename to `key_size` to match `EncryptionScheme::key_size`? pub fn key_length(&self) -> Option { @@ -67,7 +71,7 @@ impl<'a> Kdf<'a> { } /// Get [`Pbkdf2Params`] if it is the selected algorithm. - pub fn pbkdf2(&self) -> Option<&Pbkdf2Params<'a>> { + pub fn pbkdf2(&self) -> Option<&Pbkdf2Params> { match self { Self::Pbkdf2(params) => Some(params), _ => None, @@ -75,7 +79,7 @@ impl<'a> Kdf<'a> { } /// Get [`ScryptParams`] if it is the selected algorithm. - pub fn scrypt(&self) -> Option<&ScryptParams<'a>> { + pub fn scrypt(&self) -> Option<&ScryptParams> { match self { Self::Scrypt(params) => Some(params), _ => None, @@ -99,13 +103,13 @@ impl<'a> Kdf<'a> { } } -impl<'a> DecodeValue<'a> for Kdf<'a> { +impl<'a> DecodeValue<'a> for Kdf { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { AlgorithmIdentifierRef::decode_value(reader, header)?.try_into() } } -impl EncodeValue for Kdf<'_> { +impl EncodeValue for Kdf { fn value_len(&self) -> der::Result { self.oid().encoded_len()? + match self { @@ -126,24 +130,24 @@ impl EncodeValue for Kdf<'_> { } } -impl<'a> Sequence<'a> for Kdf<'a> {} +impl Sequence<'_> for Kdf {} -impl<'a> From> for Kdf<'a> { - fn from(params: Pbkdf2Params<'a>) -> Self { +impl From for Kdf { + fn from(params: Pbkdf2Params) -> Self { Kdf::Pbkdf2(params) } } -impl<'a> From> for Kdf<'a> { - fn from(params: ScryptParams<'a>) -> Self { +impl From for Kdf { + fn from(params: ScryptParams) -> Self { Kdf::Scrypt(params) } } -impl<'a> TryFrom> for Kdf<'a> { +impl TryFrom> for Kdf { type Error = der::Error; - fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result { + fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result { if let Some(params) = alg.parameters { match alg.oid { PBKDF2_OID => params.try_into().map(Self::Pbkdf2), @@ -172,11 +176,11 @@ impl<'a> TryFrom> for Kdf<'a> { /// ``` /// /// [RFC 8018 Appendix A.2]: https://tools.ietf.org/html/rfc8018#appendix-A.2 -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Pbkdf2Params<'a> { +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Pbkdf2Params { /// PBKDF2 salt // TODO(tarcieri): support `CHOICE` with `otherSource` - pub salt: &'a [u8], + pub salt: Salt, /// PBKDF2 iteration count pub iteration_count: u32, @@ -188,7 +192,7 @@ pub struct Pbkdf2Params<'a> { pub prf: Pbkdf2Prf, } -impl<'a> Pbkdf2Params<'a> { +impl Pbkdf2Params { /// Implementation defined maximum iteration count of 100,000,000. /// /// > For especially critical keys, or @@ -203,12 +207,13 @@ impl<'a> Pbkdf2Params<'a> { const INVALID_ERR: Error = Error::AlgorithmParametersInvalid { oid: PBKDF2_OID }; /// Initialize PBKDF2-SHA256 with the given iteration count and salt - pub fn hmac_with_sha256(iteration_count: u32, salt: &'a [u8]) -> Result { + pub fn hmac_with_sha256(iteration_count: u32, salt: &[u8]) -> Result { if iteration_count > Self::MAX_ITERATION_COUNT { return Err(Self::INVALID_ERR); } + Ok(Self { - salt, + salt: salt.try_into().map_err(|_| Self::INVALID_ERR)?, iteration_count, key_length: None, prf: Pbkdf2Prf::HmacWithSha256, @@ -216,15 +221,15 @@ impl<'a> Pbkdf2Params<'a> { } } -impl<'a> DecodeValue<'a> for Pbkdf2Params<'a> { +impl<'a> DecodeValue<'a> for Pbkdf2Params { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { AnyRef::decode_value(reader, header)?.try_into() } } -impl EncodeValue for Pbkdf2Params<'_> { +impl EncodeValue for Pbkdf2Params { fn value_len(&self) -> der::Result { - let len = OctetStringRef::new(self.salt)?.encoded_len()? + let len = self.salt.encoded_len()? + self.iteration_count.encoded_len()? + self.key_length.encoded_len()?; @@ -236,7 +241,7 @@ impl EncodeValue for Pbkdf2Params<'_> { } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - OctetStringRef::new(self.salt)?.encode(writer)?; + self.salt.encode(writer)?; self.iteration_count.encode(writer)?; self.key_length.encode(writer)?; @@ -248,16 +253,16 @@ impl EncodeValue for Pbkdf2Params<'_> { } } -impl<'a> Sequence<'a> for Pbkdf2Params<'a> {} +impl Sequence<'_> for Pbkdf2Params {} -impl<'a> TryFrom> for Pbkdf2Params<'a> { +impl TryFrom> for Pbkdf2Params { type Error = der::Error; - fn try_from(any: AnyRef<'a>) -> der::Result { + fn try_from(any: AnyRef<'_>) -> der::Result { any.sequence(|reader| { // TODO(tarcieri): support salt `CHOICE` w\ `AlgorithmIdentifier` Ok(Self { - salt: OctetStringRef::decode(reader)?.as_bytes(), + salt: reader.decode()?, iteration_count: reader.decode()?, key_length: reader.decode()?, prf: Option::>::decode(reader)? @@ -316,10 +321,10 @@ impl Default for Pbkdf2Prf { } } -impl<'a> TryFrom> for Pbkdf2Prf { +impl TryFrom> for Pbkdf2Prf { type Error = der::Error; - fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result { + fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result { if let Some(params) = alg.parameters { // TODO(tarcieri): support non-NULL parameters? if !params.is_null() { @@ -341,7 +346,7 @@ impl<'a> TryFrom> for Pbkdf2Prf { } } -impl<'a> From for AlgorithmIdentifierRef<'a> { +impl From for AlgorithmIdentifierRef<'_> { fn from(prf: Pbkdf2Prf) -> Self { // TODO(tarcieri): support non-NULL parameters? let parameters = der::asn1::Null; @@ -376,10 +381,10 @@ impl Encode for Pbkdf2Prf { /// ``` /// /// [RFC 7914 Section 7.1]: https://datatracker.ietf.org/doc/html/rfc7914#section-7.1 -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ScryptParams<'a> { +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ScryptParams { /// scrypt salt - pub salt: &'a [u8], + pub salt: Salt, /// CPU/Memory cost parameter `N`. pub cost_parameter: ScryptCost, @@ -394,7 +399,7 @@ pub struct ScryptParams<'a> { pub key_length: Option, } -impl<'a> ScryptParams<'a> { +impl ScryptParams { #[cfg(feature = "pbes2")] const INVALID_ERR: Error = Error::AlgorithmParametersInvalid { oid: SCRYPT_OID }; @@ -402,9 +407,9 @@ impl<'a> ScryptParams<'a> { /// and a provided salt string. // TODO(tarcieri): encapsulate `scrypt::Params`? #[cfg(feature = "pbes2")] - pub fn from_params_and_salt(params: scrypt::Params, salt: &'a [u8]) -> Result { + pub fn from_params_and_salt(params: scrypt::Params, salt: &[u8]) -> Result { Ok(Self { - salt, + salt: salt.try_into().map_err(|_| Self::INVALID_ERR)?, cost_parameter: 1 << params.log_n(), block_size: params.r().try_into().map_err(|_| Self::INVALID_ERR)?, parallelization: params.p().try_into().map_err(|_| Self::INVALID_ERR)?, @@ -413,15 +418,15 @@ impl<'a> ScryptParams<'a> { } } -impl<'a> DecodeValue<'a> for ScryptParams<'a> { +impl<'a> DecodeValue<'a> for ScryptParams { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { AnyRef::decode_value(reader, header)?.try_into() } } -impl EncodeValue for ScryptParams<'_> { +impl EncodeValue for ScryptParams { fn value_len(&self) -> der::Result { - OctetStringRef::new(self.salt)?.encoded_len()? + self.salt.encoded_len()? + self.cost_parameter.encoded_len()? + self.block_size.encoded_len()? + self.parallelization.encoded_len()? @@ -429,7 +434,7 @@ impl EncodeValue for ScryptParams<'_> { } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - OctetStringRef::new(self.salt)?.encode(writer)?; + self.salt.encode(writer)?; self.cost_parameter.encode(writer)?; self.block_size.encode(writer)?; self.parallelization.encode(writer)?; @@ -438,15 +443,15 @@ impl EncodeValue for ScryptParams<'_> { } } -impl<'a> Sequence<'a> for ScryptParams<'a> {} +impl Sequence<'_> for ScryptParams {} -impl<'a> TryFrom> for ScryptParams<'a> { +impl TryFrom> for ScryptParams { type Error = der::Error; - fn try_from(any: AnyRef<'a>) -> der::Result { + fn try_from(any: AnyRef<'_>) -> der::Result { any.sequence(|reader| { Ok(Self { - salt: OctetStringRef::decode(reader)?.as_bytes(), + salt: reader.decode()?, cost_parameter: reader.decode()?, block_size: reader.decode()?, parallelization: reader.decode()?, @@ -457,19 +462,19 @@ impl<'a> TryFrom> for ScryptParams<'a> { } #[cfg(feature = "pbes2")] -impl<'a> TryFrom> for scrypt::Params { +impl TryFrom for scrypt::Params { type Error = Error; - fn try_from(params: ScryptParams<'a>) -> Result { + fn try_from(params: ScryptParams) -> Result { scrypt::Params::try_from(¶ms) } } #[cfg(feature = "pbes2")] -impl<'a> TryFrom<&ScryptParams<'a>> for scrypt::Params { +impl TryFrom<&ScryptParams> for scrypt::Params { type Error = Error; - fn try_from(params: &ScryptParams<'a>) -> Result { + fn try_from(params: &ScryptParams) -> Result { let n = params.cost_parameter; // Compute log2 and verify its correctness diff --git a/pkcs5/src/pbes2/kdf/salt.rs b/pkcs5/src/pbes2/kdf/salt.rs new file mode 100644 index 000000000..75c5a0758 --- /dev/null +++ b/pkcs5/src/pbes2/kdf/salt.rs @@ -0,0 +1,102 @@ +//! Salt storage buffer which works on heapless `no_std` targets. +// TODO(tarcieri): use `ArrayVec` when it's available in `core`. + +use core::fmt; +use der::{DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, Writer}; + +/// Salt as used by the PBES2 KDF. +#[derive(Clone, Eq, PartialEq)] +pub struct Salt { + inner: [u8; Self::MAX_LEN], + length: Length, +} + +impl Salt { + /// Maximum length of a salt that can be stored. + pub const MAX_LEN: usize = 32; + + /// Create a new salt from the given byte slice. + pub fn new(slice: impl AsRef<[u8]>) -> Result { + let slice = slice.as_ref(); + + if slice.len() > Self::MAX_LEN { + return Err(Self::TAG.length_error()); + } + + let mut inner = [0u8; Self::MAX_LEN]; + let mut i = 0; + + while i < slice.len() { + inner[i] = slice[i]; + i += 1; + } + + Ok(Self { + inner, + length: Length::new(slice.len() as u16), + }) + } + + /// Borrow the salt data as a byte slice. + pub fn as_bytes(&self) -> &[u8] { + let length = usize::try_from(self.length).expect("should be less than Self::MAX_LEN"); + &self.inner[..length] + } + + /// Get the length of the salt data. + pub fn len(&self) -> Length { + self.length + } +} + +impl AsRef<[u8]> for Salt { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for Salt { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let length = usize::try_from(header.length)?; + + if length > Self::MAX_LEN { + return Err(Self::TAG.length_error()); + } + + let mut inner = [0u8; Self::MAX_LEN]; + reader.read_into(&mut inner[..length])?; + + Ok(Self { + inner, + length: header.length, + }) + } +} + +impl EncodeValue for Salt { + fn value_len(&self) -> Result { + Ok(self.length) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for Salt { + const TAG: Tag = Tag::OctetString; +} + +impl TryFrom<&[u8]> for Salt { + type Error = Error; + + fn try_from(slice: &[u8]) -> Result { + Self::new(slice) + } +} + +impl fmt::Debug for Salt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Salt").field(&self.as_bytes()).finish() + } +} diff --git a/pkcs5/tests/pbes2.rs b/pkcs5/tests/pbes2.rs index bb280d031..53a463881 100644 --- a/pkcs5/tests/pbes2.rs +++ b/pkcs5/tests/pbes2.rs @@ -63,14 +63,14 @@ fn decode_pbes2_pbkdf2_sha1_aes128cbc() { let params = scheme.pbes2().unwrap(); let pbkdf2_params = params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, &hex!("e8765e01e43b6bad")); + assert_eq!(pbkdf2_params.salt.as_bytes(), &hex!("e8765e01e43b6bad")); assert_eq!(pbkdf2_params.iteration_count, 2048); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha1); match params.encryption { pbes2::EncryptionScheme::Aes128Cbc { iv } => { - assert_eq!(iv, &hex!("223080a71bcd2b9a256d876c924979d2")); + assert_eq!(iv, hex!("223080a71bcd2b9a256d876c924979d2")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -83,14 +83,14 @@ fn decode_pbes2_pbkdf2_sha256_aes256cbc() { let params = scheme.pbes2().unwrap(); let pbkdf2_params = params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, &hex!("79d982e70df91a88")); + assert_eq!(pbkdf2_params.salt.as_bytes(), &hex!("79d982e70df91a88")); assert_eq!(pbkdf2_params.iteration_count, 2048); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha256); match params.encryption { pbes2::EncryptionScheme::Aes256Cbc { iv } => { - assert_eq!(iv, &hex!("b2d02d78b2efd9dff694cf8e0af40925")); + assert_eq!(iv, hex!("b2d02d78b2efd9dff694cf8e0af40925")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -103,7 +103,7 @@ fn decode_pbes2_scrypt_aes256cbc() { let params = scheme.pbes2().unwrap(); let scrypt_params = params.kdf.scrypt().unwrap(); - assert_eq!(scrypt_params.salt, &hex!("E6211E2348AD69E0")); + assert_eq!(scrypt_params.salt.as_bytes(), &hex!("E6211E2348AD69E0")); assert_eq!(scrypt_params.cost_parameter, 16384); assert_eq!(scrypt_params.block_size, 8); assert_eq!(scrypt_params.parallelization, 1); @@ -111,7 +111,7 @@ fn decode_pbes2_scrypt_aes256cbc() { match params.encryption { pbes2::EncryptionScheme::Aes256Cbc { iv } => { - assert_eq!(iv, &hex!("9BD0A6251F2254F9FD5963887C27CF01")); + assert_eq!(iv, hex!("9BD0A6251F2254F9FD5963887C27CF01")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -125,14 +125,14 @@ fn decode_pbes2_pbkdf2_sha256_desede3cbc() { let params = scheme.pbes2().unwrap(); let pbkdf2_params = params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, &hex!("32A0AE2E01BBE329")); + assert_eq!(pbkdf2_params.salt.as_bytes(), &hex!("32A0AE2E01BBE329")); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha256); assert_eq!(pbkdf2_params.iteration_count, 2048); match params.encryption { pbes2::EncryptionScheme::DesEde3Cbc { iv } => { - assert_eq!(iv, &hex!("97E8F53AB0ACA359")); + assert_eq!(iv, hex!("97E8F53AB0ACA359")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -146,14 +146,14 @@ fn decode_pbes2_pbkdf2_sha256_descbc() { let params = scheme.pbes2().unwrap(); let pbkdf2_params = params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, &hex!("09E7EDFBD9F21E2B")); + assert_eq!(pbkdf2_params.salt.as_bytes(), &hex!("09E7EDFBD9F21E2B")); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha256); assert_eq!(pbkdf2_params.iteration_count, 2048); match params.encryption { pbes2::EncryptionScheme::DesCbc { iv } => { - assert_eq!(iv, &hex!("F4AAF206A18DE7AD")); + assert_eq!(iv, hex!("F4AAF206A18DE7AD")); } other => panic!("unexpected encryption scheme: {:?}", other), } From d3170f007c2e6458185da300439816e92af63685 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 9 Aug 2023 16:57:25 +0000 Subject: [PATCH 02/11] cms: pull api changes from #1195 Signed-off-by: Arthur Gautier --- cms/tests/enveloped_data.rs | 4 ++-- cms/tests/tests_from_pkcs7_crate.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cms/tests/enveloped_data.rs b/cms/tests/enveloped_data.rs index 8d2886213..7fdf3ca6c 100644 --- a/cms/tests/enveloped_data.rs +++ b/cms/tests/enveloped_data.rs @@ -223,7 +223,7 @@ fn reencode_enveloped_data_pwri_test() { ); let enc_pbkdf2 = kdf_alg.parameters.as_ref().unwrap().to_der().unwrap(); let pbkdf2 = Pbkdf2Params::from_der(enc_pbkdf2.as_slice()).unwrap(); - assert_eq!(hex!("7F EE A8 FD 56 8E 8F 07"), pbkdf2.salt); + assert_eq!(hex!("7F EE A8 FD 56 8E 8F 07"), pbkdf2.salt.as_ref()); assert_eq!(2048, pbkdf2.iteration_count); assert_eq!( ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.3.9"), @@ -443,7 +443,7 @@ fn reencode_enveloped_data_multi_test() { ); let enc_pbkdf2 = kdf_alg.parameters.as_ref().unwrap().to_der().unwrap(); let pbkdf2 = Pbkdf2Params::from_der(enc_pbkdf2.as_slice()).unwrap(); - assert_eq!(hex!("39 04 A7 33 A0 6A 1B 27"), pbkdf2.salt); + assert_eq!(hex!("39 04 A7 33 A0 6A 1B 27"), pbkdf2.salt.as_ref()); assert_eq!(2048, pbkdf2.iteration_count); assert_eq!( ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.3.9"), diff --git a/cms/tests/tests_from_pkcs7_crate.rs b/cms/tests/tests_from_pkcs7_crate.rs index 8c75adf05..ccfebe31d 100644 --- a/cms/tests/tests_from_pkcs7_crate.rs +++ b/cms/tests/tests_from_pkcs7_crate.rs @@ -40,7 +40,7 @@ fn cms_decode_encrypted_key_example() { .to_der() .unwrap(); let pbkdf2 = Pbkdf2Params::from_der(enc_pbkdf2.as_slice()).unwrap(); - assert_eq!(hex!("ad2d4b4e87b34d67"), pbkdf2.salt); + assert_eq!(hex!("ad2d4b4e87b34d67"), pbkdf2.salt.as_ref()); assert_eq!(2048, pbkdf2.iteration_count); assert_eq!( 552u32, From f649819204d5ad72d5296b8a9a2c63f26769d7e6 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 9 Aug 2023 16:57:36 +0000 Subject: [PATCH 03/11] pkcs8: pull api changes from #1195 Signed-off-by: Arthur Gautier --- pkcs8/src/encrypted_private_key_info.rs | 6 +++--- pkcs8/src/private_key_info.rs | 2 +- pkcs8/tests/encrypted_private_key.rs | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs index d55949cad..e081c8e11 100644 --- a/pkcs8/src/encrypted_private_key_info.rs +++ b/pkcs8/src/encrypted_private_key_info.rs @@ -43,7 +43,7 @@ use der::pem::PemLabel; pub struct EncryptedPrivateKeyInfo<'a> { /// Algorithm identifier describing a password-based symmetric encryption /// scheme used to encrypt the `encrypted_data` field. - pub encryption_algorithm: EncryptionScheme<'a>, + pub encryption_algorithm: EncryptionScheme, /// Private key data pub encrypted_data: &'a [u8], @@ -74,7 +74,7 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { let mut iv = [0u8; 16]; rng.fill_bytes(&mut iv); - let pbes2_params = pbes2::Parameters::scrypt_aes256cbc(Default::default(), &salt, &iv)?; + let pbes2_params = pbes2::Parameters::scrypt_aes256cbc(Default::default(), &salt, iv)?; EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, doc) } @@ -82,7 +82,7 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { /// from the provided password and [`pbes2::Parameters`]. #[cfg(feature = "encryption")] pub(crate) fn encrypt_with( - pbes2_params: pbes2::Parameters<'a>, + pbes2_params: pbes2::Parameters, password: impl AsRef<[u8]>, doc: &[u8], ) -> Result { diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index ecae624df..ec4c6ec04 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -149,7 +149,7 @@ impl<'a> PrivateKeyInfo<'a> { #[cfg(feature = "encryption")] pub fn encrypt_with_params( &self, - pbes2_params: pbes2::Parameters<'_>, + pbes2_params: pbes2::Parameters, password: impl AsRef<[u8]>, ) -> Result { let der = Zeroizing::new(self.to_der()?); diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index dbe0a18e7..9d601c749 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -89,14 +89,14 @@ fn decode_ed25519_encpriv_aes128_pbkdf2_sha1_der() { let pbes2_params = pk.encryption_algorithm.pbes2().unwrap(); let pbkdf2_params = pbes2_params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, hex!("e8765e01e43b6bad")); + assert_eq!(pbkdf2_params.salt.as_ref(), hex!("e8765e01e43b6bad")); assert_eq!(pbkdf2_params.iteration_count, 2048); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha1); match pbes2_params.encryption { pbes2::EncryptionScheme::Aes128Cbc { iv } => { - assert_eq!(iv, &hex!("223080a71bcd2b9a256d876c924979d2")); + assert_eq!(iv, hex!("223080a71bcd2b9a256d876c924979d2")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -121,14 +121,14 @@ fn decode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { let pbes2_params = pk.encryption_algorithm.pbes2().unwrap(); let pbkdf2_params = pbes2_params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, hex!("79d982e70df91a88")); + assert_eq!(pbkdf2_params.salt.as_ref(), hex!("79d982e70df91a88")); assert_eq!(pbkdf2_params.iteration_count, 2048); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha256); match pbes2_params.encryption { pbes2::EncryptionScheme::Aes256Cbc { iv } => { - assert_eq!(iv, &hex!("b2d02d78b2efd9dff694cf8e0af40925")); + assert_eq!(iv, hex!("b2d02d78b2efd9dff694cf8e0af40925")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -164,7 +164,7 @@ fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { let pbes2_params = pkcs5::pbes2::Parameters::pbkdf2_sha256_aes256cbc( 2048, &hex!("79d982e70df91a88"), - &hex!("b2d02d78b2efd9dff694cf8e0af40925"), + hex!("b2d02d78b2efd9dff694cf8e0af40925"), ) .unwrap(); @@ -185,7 +185,7 @@ fn encrypt_ed25519_der_encpriv_aes256_scrypt() { let scrypt_params = pkcs5::pbes2::Parameters::scrypt_aes256cbc( pkcs5::scrypt::Params::new(15, 8, 1, 32).unwrap(), &hex!("E6211E2348AD69E0"), - &hex!("9BD0A6251F2254F9FD5963887C27CF01"), + hex!("9BD0A6251F2254F9FD5963887C27CF01"), ) .unwrap(); From d6fa56b93ff889602eb852c2f2ca3c6acf899613 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 4 Aug 2023 04:24:58 +0000 Subject: [PATCH 04/11] pkcs8: provide `PrivateKeyInfoRef`/`PrivateKeyInfoOwned` Signed-off-by: Arthur Gautier --- pkcs8/src/lib.rs | 2 +- pkcs8/src/private_key_info.rs | 155 +++++++++++++++++++++------ 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, 163 insertions(+), 67 deletions(-) diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index 33ceef8e2..dcc4bbbfc 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, }; diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index ec4c6ec04..91670407a 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -1,15 +1,16 @@ //! 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, + BytesRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, TagMode, + TagNumber, Writer, }; +use spki::AlgorithmIdentifier; #[cfg(feature = "alloc")] -use der::SecretDocument; +use der::{asn1::Any, BytesOwned, SecretDocument}; #[cfg(feature = "encryption")] use { @@ -90,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, @@ -124,7 +125,12 @@ impl<'a> PrivateKeyInfo<'a> { Version::V1 } } - +} +impl<'a, Params, Key> PrivateKeyInfo +where + Params: der::Choice<'a> + Encode, + Key: TryFrom<&'a [u8], Error = der::Error> + AsRef<[u8]>, +{ /// Encrypt this private key using a symmetric encryption key derived /// from the provided password. /// @@ -155,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, @@ -170,21 +183,27 @@ impl<'a> PrivateKeyInfo<'a> { } } -impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { +impl<'a, Params, Key> DecodeValue<'a> for PrivateKeyInfo +where + Params: der::Choice<'a> + Encode, + Key: TryFrom<&'a [u8], 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()) + .and_then(Key::try_from) }) .transpose()?; @@ -213,26 +232,39 @@ impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { } } -impl EncodeValue for PrivateKeyInfo<'_> { +impl<'a, Params, Key> EncodeValue for PrivateKeyInfo +where + Params: der::Choice<'a> + 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> + Encode, + Key: TryFrom<&'a [u8], Error = der::Error> + AsRef<[u8]>, +{ +} -impl<'a> TryFrom<&'a [u8]> for PrivateKeyInfo<'a> { +impl<'a, Params, Key> TryFrom<&'a [u8]> for PrivateKeyInfo +where + Params: der::Choice<'a> + Encode, + Key: TryFrom<&'a [u8], Error = der::Error> + AsRef<[u8]>, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -240,7 +272,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()) @@ -251,45 +287,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> + Encode, + Key: TryFrom<&'a [u8], Error = der::Error> + 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> + Encode, + Key: TryFrom<&'a [u8], Error = der::Error> + 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 [`BytesRef`] params. +pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, BytesRef<'a>>; + +/// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and [`BytesOwned`] params. +#[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 f6165f696..312b2dbd8 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; @@ -49,7 +49,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()) @@ -81,17 +81,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)?) } } @@ -116,7 +116,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 @@ -142,6 +142,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 9d601c749..7f44a7a23 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; @@ -168,7 +168,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(); @@ -189,7 +189,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 1ef0f7361..b71f06d48 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; @@ -43,7 +43,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()); @@ -59,14 +59,14 @@ 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 vector from RFC8410 Section 10.3: // 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); @@ -74,7 +74,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")[..] ); } @@ -90,29 +90,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); @@ -120,7 +123,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")[..] ); } @@ -128,7 +131,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); } @@ -136,52 +139,52 @@ fn encode_ec_p256_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_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 1d0e9062f730593be1405c1922979ba09c54c9a5 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 4 Aug 2023 04:34:25 +0000 Subject: [PATCH 05/11] pkcs8: expose `PrivateKeyInfoOwned` 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 dcc4bbbfc..6578e3a18 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -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, }; From 738f7124a02abafb491f72d77262ca1961ca9f69 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 4 Aug 2023 04:37:54 +0000 Subject: [PATCH 06/11] pkcs8: fixup comment Signed-off-by: Arthur Gautier --- pkcs8/src/private_key_info.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index 91670407a..278f5832d 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -352,10 +352,10 @@ where } } -/// [`PrivateKeyInfo`] with [`AnyRef`] algorithm parameters, and [`BytesRef`] params. +/// [`PrivateKeyInfo`] with [`AnyRef`] algorithm parameters, and [`BytesRef`] key. pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, BytesRef<'a>>; -/// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and [`BytesOwned`] params. +/// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and [`BytesOwned`] key. #[cfg(feature = "alloc")] pub type PrivateKeyInfoOwned = PrivateKeyInfo; From 0b96453433b46df43dd625a83321ae9bd800e47d Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 4 Aug 2023 19:09:12 +0000 Subject: [PATCH 07/11] pkcs8: move implement to `&[u8]`/`Box<[u8]>` Signed-off-by: Arthur Gautier --- pkcs8/src/private_key_info.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index 278f5832d..69a912ec8 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -4,13 +4,16 @@ use crate::{Error, Result, Version}; use core::fmt; use der::{ asn1::{AnyRef, BitStringRef, ContextSpecific, OctetStringRef}, - BytesRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, TagMode, - TagNumber, Writer, + Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, TagMode, TagNumber, + Writer, }; use spki::AlgorithmIdentifier; #[cfg(feature = "alloc")] -use der::{asn1::Any, BytesOwned, SecretDocument}; +use { + alloc::boxed::Box, + der::{asn1::Any, SecretDocument}, +}; #[cfg(feature = "encryption")] use { @@ -129,7 +132,7 @@ impl PrivateKeyInfo { impl<'a, Params, Key> PrivateKeyInfo where Params: der::Choice<'a> + Encode, - Key: TryFrom<&'a [u8], Error = der::Error> + AsRef<[u8]>, + Key: From<&'a [u8]> + AsRef<[u8]>, { /// Encrypt this private key using a symmetric encryption key derived /// from the provided password. @@ -186,7 +189,7 @@ where impl<'a, Params, Key> DecodeValue<'a> for PrivateKeyInfo where Params: der::Choice<'a> + Encode, - Key: TryFrom<&'a [u8], Error = der::Error>, + Key: From<&'a [u8]>, { fn decode_value>( reader: &mut R, @@ -203,7 +206,7 @@ where .map(|bs| { bs.as_bytes() .ok_or_else(|| der::Tag::BitString.value_error()) - .and_then(Key::try_from) + .map(Key::from) }) .transpose()?; @@ -256,14 +259,14 @@ where impl<'a, Params, Key> Sequence<'a> for PrivateKeyInfo where Params: der::Choice<'a> + Encode, - Key: TryFrom<&'a [u8], Error = der::Error> + AsRef<[u8]>, + Key: From<&'a [u8]> + AsRef<[u8]>, { } impl<'a, Params, Key> TryFrom<&'a [u8]> for PrivateKeyInfo where Params: der::Choice<'a> + Encode, - Key: TryFrom<&'a [u8], Error = der::Error> + AsRef<[u8]>, + Key: From<&'a [u8]> + AsRef<[u8]>, { type Error = Error; @@ -290,7 +293,7 @@ where impl<'a, Params, Key> TryFrom> for SecretDocument where Params: der::Choice<'a> + Encode, - Key: TryFrom<&'a [u8], Error = der::Error> + AsRef<[u8]>, + Key: From<&'a [u8]> + AsRef<[u8]>, { type Error = Error; @@ -303,7 +306,7 @@ where impl<'a, Params, Key> TryFrom<&PrivateKeyInfo> for SecretDocument where Params: der::Choice<'a> + Encode, - Key: TryFrom<&'a [u8], Error = der::Error> + AsRef<[u8]>, + Key: From<&'a [u8]> + AsRef<[u8]>, { type Error = Error; @@ -352,12 +355,12 @@ where } } -/// [`PrivateKeyInfo`] with [`AnyRef`] algorithm parameters, and [`BytesRef`] key. -pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, BytesRef<'a>>; +/// [`PrivateKeyInfo`] with [`AnyRef`] algorithm parameters, and `&[u8]` key. +pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, &'a [u8]>; -/// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and [`BytesOwned`] key. +/// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and `Box<[u8]>` key. #[cfg(feature = "alloc")] -pub type PrivateKeyInfoOwned = PrivateKeyInfo; +pub type PrivateKeyInfoOwned = PrivateKeyInfo>; #[cfg(feature = "alloc")] mod allocating { From 0d133f5413700060122873ff23ed32ae70ebd50e Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 6 Aug 2023 03:49:22 +0000 Subject: [PATCH 08/11] 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 69a912ec8..b5b03a95f 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -94,7 +94,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, @@ -105,8 +105,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. @@ -129,7 +129,7 @@ impl PrivateKeyInfo { } } } -impl<'a, Params, Key> PrivateKeyInfo +impl<'a, Params, Key> PrivateKeyInfoInner where Params: der::Choice<'a> + Encode, Key: From<&'a [u8]> + AsRef<[u8]>, @@ -166,7 +166,7 @@ where } } -impl<'a, Params, Key> PrivateKeyInfo +impl<'a, Params, Key> PrivateKeyInfoInner where Params: der::Choice<'a> + Encode, Key: AsRef<[u8]>, @@ -186,15 +186,12 @@ where } } -impl<'a, Params, Key> DecodeValue<'a> for PrivateKeyInfo +impl<'a, Params, Key> DecodeValue<'a> for PrivateKeyInfoInner where Params: der::Choice<'a> + Encode, Key: From<&'a [u8]>, { - 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)?; @@ -235,7 +232,7 @@ where } } -impl<'a, Params, Key> EncodeValue for PrivateKeyInfo +impl<'a, Params, Key> EncodeValue for PrivateKeyInfoInner where Params: der::Choice<'a> + Encode, Key: AsRef<[u8]>, @@ -256,14 +253,14 @@ where } } -impl<'a, Params, Key> Sequence<'a> for PrivateKeyInfo +impl<'a, Params, Key> Sequence<'a> for PrivateKeyInfoInner where Params: der::Choice<'a> + 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> + Encode, Key: From<&'a [u8]> + AsRef<[u8]>, @@ -275,13 +272,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) @@ -290,38 +287,38 @@ where } #[cfg(feature = "alloc")] -impl<'a, Params, Key> TryFrom> for SecretDocument +impl<'a, Params, Key> TryFrom> for SecretDocument where Params: der::Choice<'a> + 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> + 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]>, @@ -337,7 +334,7 @@ where } #[cfg(feature = "subtle")] -impl Eq for PrivateKeyInfo +impl Eq for PrivateKeyInfoInner where Params: Eq, Key: AsRef<[u8]> + Eq, @@ -345,7 +342,7 @@ where } #[cfg(feature = "subtle")] -impl PartialEq for PrivateKeyInfo +impl PartialEq for PrivateKeyInfoInner where Params: Eq, Key: PartialEq + AsRef<[u8]>, @@ -355,19 +352,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 { @@ -379,9 +376,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 312b2dbd8..f6165f696 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; @@ -49,7 +49,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()) @@ -81,17 +81,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)?) } } @@ -116,7 +116,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 @@ -142,6 +142,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 7f44a7a23..9d601c749 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; @@ -168,7 +168,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(); @@ -189,7 +189,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 b71f06d48..22b8e4bec 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; @@ -43,7 +43,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()); @@ -66,7 +66,7 @@ fn decode_ec_p256_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); @@ -90,7 +90,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); @@ -103,7 +103,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()); @@ -115,7 +115,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); @@ -131,7 +131,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); } @@ -139,52 +139,52 @@ fn encode_ec_p256_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()); } #[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 fee6a2c4df7b71850282934bd3a523603863d2cb Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 7 Aug 2023 16:11:10 +0000 Subject: [PATCH 09/11] 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 1df903c8e9f4f88e83fe4763670b0b18f667e35c Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 7 Aug 2023 22:29:05 +0000 Subject: [PATCH 10/11] pkcs8: bring `RefToOwned for &'a [u8]` Signed-off-by: Arthur Gautier --- pkcs8/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkcs8/Cargo.toml b/pkcs8/Cargo.toml index 9d591f53f..63f59c0a8 100644 --- a/pkcs8/Cargo.toml +++ b/pkcs8/Cargo.toml @@ -16,7 +16,7 @@ edition = "2021" rust-version = "1.65" [dependencies] -der = { version = "0.7", features = ["oid"] } +der = { version = "0.7.8", features = ["oid"] } spki = { version = "0.7.1" } # optional dependencies From d3e42e55b5dddb6d175d37263f32b77d9372775a Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 9 Aug 2023 21:27:11 +0000 Subject: [PATCH 11/11] 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 | 6 +- pkcs8/src/traits.rs | 10 ++-- pkcs8/tests/encrypted_private_key.rs | 23 +++++--- 5 files changed, 77 insertions(+), 42 deletions(-) diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs index e081c8e11..bad1df6a8 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 { @@ -40,23 +40,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()?) } @@ -75,7 +78,7 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { rng.fill_bytes(&mut iv); let pbes2_params = pbes2::Parameters::scrypt_aes256cbc(Default::default(), &salt, iv)?; - EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, doc) + Self::encrypt_with(pbes2_params, password, doc) } /// Encrypt this private key using a symmetric encryption key derived @@ -90,42 +93,51 @@ 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> { - fn decode_value>( - reader: &mut R, - header: Header, - ) -> der::Result> { +impl<'a, Data> DecodeValue<'a> for EncryptedPrivateKeyInfo +where + Data: From<&'a [u8]>, +{ + 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]>, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -133,7 +145,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) @@ -142,24 +154,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 b5b03a95f..05048f97c 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -17,7 +17,7 @@ use { #[cfg(feature = "encryption")] use { - crate::EncryptedPrivateKeyInfo, + crate::EncryptedPrivateKeyInfoRef, der::zeroize::Zeroizing, pkcs5::pbes2, rand_core::{CryptoRng, RngCore}, @@ -150,7 +150,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 @@ -162,7 +162,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 f6165f696..62d85f1d3 100644 --- a/pkcs8/src/traits.rs +++ b/pkcs8/src/traits.rs @@ -7,7 +7,7 @@ use der::SecretDocument; #[cfg(feature = "encryption")] use { - crate::EncryptedPrivateKeyInfo, + crate::EncryptedPrivateKeyInfoRef, rand_core::{CryptoRng, RngCore}, }; @@ -34,7 +34,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()) } @@ -66,7 +66,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) } @@ -109,7 +109,7 @@ pub trait EncodePrivateKey { rng: impl CryptoRng + RngCore, 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`]. @@ -129,7 +129,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 9d601c749..7582dcf2b 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; @@ -79,7 +79,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(), @@ -111,7 +111,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(), @@ -145,7 +146,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); } @@ -153,7 +154,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); } @@ -200,7 +201,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() @@ -210,7 +212,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() @@ -220,7 +223,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); } @@ -228,7 +232,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); }