diff --git a/Cargo.lock b/Cargo.lock index 70e3ed8ad..5dae22193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -387,7 +387,7 @@ dependencies = [ "hex-literal", "p256", "pem-rfc7468", - "pkcs5 0.8.0-rc.0", + "pkcs5", "rand", "rsa", "sha1", @@ -569,7 +569,7 @@ dependencies = [ [[package]] name = "ecdsa" version = "0.17.0-pre.7" -source = "git+https://github.com/RustCrypto/signatures#cf34cd2ffdbf5579b3fa2d1a5361464484e86ee3" +source = "git+https://github.com/baloo/signatures?branch=baloo/pkcs8/api-change#2ec8160db97f1cdbd656e6b411683011f5d0f3bf" dependencies = [ "der", "digest", @@ -588,8 +588,7 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" version = "0.14.0-pre.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed8e96bb573517f42470775f8ef1b9cd7595de52ba7a8e19c48325a92c8fe4f" +source = "git+https://github.com/baloo/traits.git?branch=baloo/elliptic-curve/pkcs8-API-break#df6f7ab4b577adcc68e0a5a1a50f0d17b3dfc949" dependencies = [ "base16ct", "crypto-bigint", @@ -1081,7 +1080,7 @@ dependencies = [ "der", "digest", "hex-literal", - "pkcs5 0.8.0-rc.1", + "pkcs5", "pkcs8", "sha2", "spki", @@ -1090,16 +1089,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "pkcs5" -version = "0.8.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f7844403c0bf02e9a4a3fbb8015f1f6f2f1eb221ffaafd4a8bfdc7143c05e3" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkcs5" version = "0.8.0-rc.1" @@ -1124,7 +1113,7 @@ version = "0.11.0-rc.0" dependencies = [ "der", "hex-literal", - "pkcs5 0.8.0-rc.1", + "pkcs5", "rand_core", "spki", "subtle", @@ -1303,7 +1292,7 @@ checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca" [[package]] name = "rfc6979" version = "0.5.0-pre.4" -source = "git+https://github.com/RustCrypto/signatures#cf34cd2ffdbf5579b3fa2d1a5361464484e86ee3" +source = "git+https://github.com/baloo/signatures?branch=baloo/pkcs8/api-change#2ec8160db97f1cdbd656e6b411683011f5d0f3bf" dependencies = [ "hmac", "subtle", @@ -1334,8 +1323,7 @@ dependencies = [ [[package]] name = "rsa" version = "0.10.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e864e43f5d003321ab452feea6450f9611d7be6726489b4ec051da34774c62" +source = "git+https://github.com/baloo/RSA?branch=baloo/pkcs8/api-changes#40113d8f924edc984a78449f244c6b47659bdc65" dependencies = [ "const-oid", "digest", diff --git a/Cargo.toml b/Cargo.toml index a59a9dcb6..b496c0903 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,4 +60,9 @@ x509-cert = { path = "./x509-cert" } x509-ocsp = { path = "./x509-ocsp" } # Temp patches to external crates -ecdsa = { git = "https://github.com/RustCrypto/signatures" } +# https://github.com/RustCrypto/signatures/pull/851 +ecdsa = { git = "https://github.com/baloo/signatures", branch = "baloo/pkcs8/api-change" } +# https://github.com/RustCrypto/RSA/pull/446 +rsa = { git = "https://github.com/baloo/RSA", branch = "baloo/pkcs8/api-changes" } +# https://github.com/RustCrypto/traits/pull/1650 +elliptic-curve = { git = "https://github.com/baloo/traits.git", branch ="baloo/elliptic-curve/pkcs8-API-break" } diff --git a/cms/Cargo.toml b/cms/Cargo.toml index 1d1be5ba0..eed22cb25 100644 --- a/cms/Cargo.toml +++ b/cms/Cargo.toml @@ -35,7 +35,7 @@ zeroize = { version = "1.8.1", optional = true } getrandom = "0.2" hex-literal = "0.4" pem-rfc7468 = "1.0.0-rc.1" -pkcs5 = "=0.8.0-rc.0" +pkcs5 = "0.8.0-rc.1" rand = "0.8.5" rsa = { version = "=0.10.0-pre.2", features = ["sha2"] } ecdsa = { version = "=0.17.0-pre.7", features = ["digest", "pem"] } diff --git a/pkcs1/src/private_key.rs b/pkcs1/src/private_key.rs index d7a7bb554..e26afd66f 100644 --- a/pkcs1/src/private_key.rs +++ b/pkcs1/src/private_key.rs @@ -6,8 +6,8 @@ pub(crate) mod other_prime_info; use crate::{Error, Result, RsaPublicKey, Version}; use core::fmt; use der::{ - asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, - Writer, + asn1::{OctetStringRef, UintRef}, + Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer, }; #[cfg(feature = "alloc")] @@ -172,6 +172,14 @@ impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> { } } +impl<'a> TryFrom> for RsaPrivateKey<'a> { + type Error = Error; + + fn try_from(bytes: OctetStringRef<'a>) -> Result { + Ok(Self::from_der(bytes.as_bytes())?) + } +} + impl fmt::Debug for RsaPrivateKey<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RsaPrivateKey") diff --git a/pkcs1/src/traits.rs b/pkcs1/src/traits.rs index 9276e0b04..9f941310c 100644 --- a/pkcs1/src/traits.rs +++ b/pkcs1/src/traits.rs @@ -15,7 +15,7 @@ use { #[cfg(feature = "pkcs8")] use { crate::{ALGORITHM_ID, ALGORITHM_OID}, - der::asn1::BitStringRef, + der::asn1::{BitStringRef, OctetStringRef}, }; #[cfg(feature = "std")] @@ -157,10 +157,11 @@ pub trait EncodeRsaPublicKey { #[cfg(feature = "pkcs8")] impl DecodeRsaPrivateKey for T where - T: for<'a> TryFrom, Error = pkcs8::Error>, + T: for<'a> TryFrom, Error = pkcs8::Error>, { fn from_pkcs1_der(private_key: &[u8]) -> Result { - Ok(Self::try_from(pkcs8::PrivateKeyInfo { + let private_key = OctetStringRef::new(private_key)?; + Ok(Self::try_from(pkcs8::PrivateKeyInfoRef { algorithm: ALGORITHM_ID, private_key, public_key: None, @@ -185,9 +186,9 @@ where impl EncodeRsaPrivateKey for T { fn to_pkcs1_der(&self) -> Result { let pkcs8_doc = self.to_pkcs8_der()?; - let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(pkcs8_doc.as_bytes())?; + let pkcs8_key = pkcs8::PrivateKeyInfoRef::from_der(pkcs8_doc.as_bytes())?; pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; - RsaPrivateKey::from_der(pkcs8_key.private_key)?.try_into() + RsaPrivateKey::from_der(pkcs8_key.private_key.as_bytes())?.try_into() } } diff --git a/pkcs12/tests/cert_tests.rs b/pkcs12/tests/cert_tests.rs index defa936ce..c25f8d390 100644 --- a/pkcs12/tests/cert_tests.rs +++ b/pkcs12/tests/cert_tests.rs @@ -13,7 +13,7 @@ use pkcs8::{ self, pbes2::{AES_256_CBC_OID, HMAC_WITH_SHA256_OID, PBES2_OID, PBKDF2_OID}, }, - EncryptedPrivateKeyInfo, + EncryptedPrivateKeyInfoRef, }; use spki::AlgorithmIdentifierOwned; @@ -242,9 +242,9 @@ fn decode_sample_pfx() { for safe_bag in safe_bags { match safe_bag.bag_id { pkcs12::PKCS_12_PKCS8_KEY_BAG_OID => { - let cs: ContextSpecific = + let cs: ContextSpecific> = ContextSpecific::from_der(&safe_bag.bag_value).unwrap(); - let mut ciphertext = cs.value.encrypted_data.to_vec(); + let mut ciphertext = cs.value.encrypted_data.as_bytes().to_vec(); let plaintext = cs .value .encryption_algorithm @@ -628,9 +628,9 @@ fn decode_sample_pfx2() { for safe_bag in safe_bags { match safe_bag.bag_id { pkcs12::PKCS_12_PKCS8_KEY_BAG_OID => { - let cs: ContextSpecific = + let cs: ContextSpecific> = ContextSpecific::from_der(&safe_bag.bag_value).unwrap(); - let mut ciphertext = cs.value.encrypted_data.to_vec(); + let mut ciphertext = cs.value.encrypted_data.as_bytes().to_vec(); let plaintext = cs .value .encryption_algorithm diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs index 19575bf2f..9e4ec471f 100644 --- a/pkcs8/src/encrypted_private_key_info.rs +++ b/pkcs8/src/encrypted_private_key_info.rs @@ -3,13 +3,13 @@ use crate::{Error, Result}; use core::fmt; use der::{ - asn1::OctetStringRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, - Sequence, Writer, + asn1::OctetStringRef, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, + Reader, Sequence, Writer, }; use pkcs5::EncryptionScheme; #[cfg(feature = "alloc")] -use der::SecretDocument; +use der::{asn1::OctetString, SecretDocument}; #[cfg(feature = "encryption")] use {pkcs5::pbes2, rand_core::CryptoRngCore}; @@ -37,23 +37,27 @@ 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: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a, + Data: AsRef<[u8]>, +{ /// Attempt to decrypt this encrypted private key using the provided /// password to derive an encryption key. #[cfg(feature = "encryption")] pub fn decrypt(&self, password: impl AsRef<[u8]>) -> Result { Ok(self .encryption_algorithm - .decrypt(password, self.encrypted_data)? + .decrypt(password, self.encrypted_data.as_ref())? .try_into()?) } @@ -66,7 +70,7 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { doc: &[u8], ) -> Result { let pbes2_params = pbes2::Parameters::recommended(rng); - EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, doc) + EncryptedPrivateKeyInfoOwned::encrypt_with(pbes2_params, password, doc) } /// Encrypt this private key using a symmetric encryption key derived @@ -78,47 +82,56 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { doc: &[u8], ) -> Result { let encrypted_data = pbes2_params.encrypt(password, doc)?; + let encrypted_data = OctetStringRef::new(&encrypted_data)?; EncryptedPrivateKeyInfo { encryption_algorithm: pbes2_params.into(), - encrypted_data: &encrypted_data, + encrypted_data, } .try_into() } } -impl<'a> DecodeValue<'a> for EncryptedPrivateKeyInfo<'a> { +impl<'a, Data> DecodeValue<'a> for EncryptedPrivateKeyInfo +where + Data: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, +{ type Error = der::Error; - fn decode_value>( - reader: &mut R, - header: Header, - ) -> der::Result> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { reader.read_nested(header.length, |reader| { Ok(Self { encryption_algorithm: reader.decode()?, - encrypted_data: OctetStringRef::decode(reader)?.as_bytes(), + encrypted_data: reader.decode()?, }) }) } } -impl EncodeValue for EncryptedPrivateKeyInfo<'_> { +impl EncodeValue for EncryptedPrivateKeyInfo +where + Data: EncodeValue + FixedTag, +{ fn value_len(&self) -> der::Result { - self.encryption_algorithm.encoded_len()? - + OctetStringRef::new(self.encrypted_data)?.encoded_len()? + self.encryption_algorithm.encoded_len()? + self.encrypted_data.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.encryption_algorithm.encode(writer)?; - OctetStringRef::new(self.encrypted_data)?.encode(writer)?; + self.encrypted_data.encode(writer)?; Ok(()) } } -impl<'a> Sequence<'a> for EncryptedPrivateKeyInfo<'a> {} +impl<'a, Data> Sequence<'a> for EncryptedPrivateKeyInfo where + Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a +{ +} -impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> { +impl<'a, Data> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo +where + Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -126,7 +139,7 @@ impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> { } } -impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> { +impl fmt::Debug for EncryptedPrivateKeyInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EncryptedPrivateKeyInfo") .field("encryption_algorithm", &self.encryption_algorithm) @@ -135,24 +148,37 @@ impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> { } #[cfg(feature = "alloc")] -impl TryFrom> for SecretDocument { +impl<'a, Data> TryFrom> for SecretDocument +where + Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a, +{ 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: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a, +{ 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 [`OctetStringRef`] encrypted data. +pub type EncryptedPrivateKeyInfoRef<'a> = EncryptedPrivateKeyInfo>; + +#[cfg(feature = "alloc")] +/// [`EncryptedPrivateKeyInfo`] with [`OctetString`] encrypted data. +pub type EncryptedPrivateKeyInfoOwned = EncryptedPrivateKeyInfo; diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index 33ceef8e2..adcd91ce6 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -85,7 +85,7 @@ pub(crate) mod encrypted_private_key_info; pub use crate::{ error::{Error, Result}, - private_key_info::PrivateKeyInfo, + private_key_info::{PrivateKeyInfo, PrivateKeyInfoRef}, traits::DecodePrivateKey, version::Version, }; @@ -96,7 +96,7 @@ pub use spki::{ #[cfg(feature = "alloc")] pub use { - crate::traits::EncodePrivateKey, + crate::{private_key_info::PrivateKeyInfoOwned, traits::EncodePrivateKey}, der::{Document, SecretDocument}, spki::EncodePublicKey, }; @@ -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 03b7ca162..9d6392e99 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -1,19 +1,24 @@ //! 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, + Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence, TagMode, + TagNumber, Writer, }; +use spki::AlgorithmIdentifier; #[cfg(feature = "alloc")] -use der::SecretDocument; +use der::{ + asn1::{Any, BitString, OctetString}, + SecretDocument, +}; #[cfg(feature = "encryption")] use { - crate::EncryptedPrivateKeyInfo, der::zeroize::Zeroizing, pkcs5::pbes2, rand_core::CryptoRngCore, + crate::EncryptedPrivateKeyInfoRef, der::zeroize::Zeroizing, pkcs5::pbes2, + rand_core::CryptoRngCore, }; #[cfg(feature = "pem")] @@ -87,23 +92,23 @@ const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1; /// [RFC 5208 Section 5]: https://tools.ietf.org/html/rfc5208#section-5 /// [RFC 5958 Section 2]: https://datatracker.ietf.org/doc/html/rfc5958#section-2 #[derive(Clone)] -pub struct PrivateKeyInfo<'a> { +pub struct PrivateKeyInfo { /// X.509 `AlgorithmIdentifier` for the private key type. - pub algorithm: AlgorithmIdentifierRef<'a>, + pub algorithm: AlgorithmIdentifier, /// Private key data. - pub private_key: &'a [u8], + pub private_key: Key, /// Public key data, optionally available if version is V2. - pub public_key: Option<&'a [u8]>, + pub public_key: Option, } -impl<'a> PrivateKeyInfo<'a> { +impl PrivateKeyInfo { /// Create a new PKCS#8 [`PrivateKeyInfo`] message. /// /// This is a helper method which initializes `attributes` and `public_key` /// to `None`, helpful if you aren't using those. - pub fn new(algorithm: AlgorithmIdentifierRef<'a>, private_key: &'a [u8]) -> Self { + pub fn new(algorithm: AlgorithmIdentifier, private_key: Key) -> Self { Self { algorithm, private_key, @@ -121,7 +126,16 @@ impl<'a> PrivateKeyInfo<'a> { Version::V1 } } +} +impl<'a, Params, Key, PubKey> PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, +{ /// Encrypt this private key using a symmetric encryption key derived /// from the provided password. /// @@ -138,7 +152,7 @@ impl<'a> PrivateKeyInfo<'a> { 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 @@ -150,42 +164,44 @@ impl<'a> PrivateKeyInfo<'a> { 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()) } +} +impl<'a, Params, Key, PubKey> PrivateKeyInfo +where + Params: der::Choice<'a> + Encode, + PubKey: BitStringLike, +{ /// Get a `BIT STRING` representation of the public key, if present. - fn public_key_bit_string(&self) -> der::Result>>> { - self.public_key - .map(|pk| { - BitStringRef::from_bytes(pk).map(|value| ContextSpecific { - tag_number: PUBLIC_KEY_TAG, - tag_mode: TagMode::Implicit, - value, - }) - }) - .transpose() + fn public_key_bit_string(&self) -> Option>> { + self.public_key.as_ref().map(|pk| { + let value = pk.as_bit_string(); + ContextSpecific { + tag_number: PUBLIC_KEY_TAG, + tag_mode: TagMode::Implicit, + value, + } + }) } } -impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { +impl<'a, Params, Key, PubKey> DecodeValue<'a> for PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, +{ type Error = der::Error; - fn decode_value>( - reader: &mut R, - header: Header, - ) -> der::Result> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { reader.read_nested(header.length, |reader| { // Parse and validate `version` INTEGER. let version = Version::decode(reader)?; let algorithm = reader.decode()?; - let private_key = OctetStringRef::decode(reader)?.into(); - let public_key = reader - .context_specific::>(PUBLIC_KEY_TAG, TagMode::Implicit)? - .map(|bs| { - bs.as_bytes() - .ok_or_else(|| der::Tag::BitString.value_error()) - }) - .transpose()?; + let private_key = Key::decode(reader)?; + let public_key = + reader.context_specific::(PUBLIC_KEY_TAG, TagMode::Implicit)?; if version.has_public_key() != public_key.is_some() { return Err(reader.error( @@ -212,26 +228,46 @@ impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { } } -impl EncodeValue for PrivateKeyInfo<'_> { +impl<'a, Params, Key, PubKey> EncodeValue for PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: EncodeValue + FixedTag, + PubKey: BitStringLike, +{ fn value_len(&self) -> der::Result { self.version().encoded_len()? + self.algorithm.encoded_len()? - + OctetStringRef::new(self.private_key)?.encoded_len()? - + self.public_key_bit_string()?.encoded_len()? + + self.private_key.encoded_len()? + + self.public_key_bit_string().encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.version().encode(writer)?; self.algorithm.encode(writer)?; - OctetStringRef::new(self.private_key)?.encode(writer)?; - self.public_key_bit_string()?.encode(writer)?; + self.private_key.encode(writer)?; + self.public_key_bit_string().encode(writer)?; Ok(()) } } -impl<'a> Sequence<'a> for PrivateKeyInfo<'a> {} +impl<'a, Params, Key, PubKey> Sequence<'a> for PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, +{ +} -impl<'a> TryFrom<&'a [u8]> for PrivateKeyInfo<'a> { +impl<'a, Params, Key, PubKey> TryFrom<&'a [u8]> for PrivateKeyInfo +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -239,7 +275,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, + PubKey: fmt::Debug, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PrivateKeyInfo") .field("version", &self.version()) @@ -250,45 +290,130 @@ impl<'a> fmt::Debug for PrivateKeyInfo<'a> { } #[cfg(feature = "alloc")] -impl TryFrom> for SecretDocument { +impl<'a, Params, Key, PubKey> TryFrom> for SecretDocument +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, +{ 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, PubKey> TryFrom<&PrivateKeyInfo> for SecretDocument +where + Params: der::Choice<'a, Error = der::Error> + Encode, + Key: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + Key: EncodeValue, + PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, + PubKey: BitStringLike, +{ type Error = Error; - fn try_from(private_key: &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]>, + PubKey: PartialEq, +{ 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, + PubKey: Eq, +{ +} #[cfg(feature = "subtle")] -impl<'a> PartialEq for PrivateKeyInfo<'a> { +impl PartialEq for PrivateKeyInfo +where + Params: Eq, + Key: PartialEq + AsRef<[u8]>, + PubKey: PartialEq, +{ fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } + +/// [`PrivateKeyInfo`] with [`AnyRef`] algorithm parameters, and `&[u8]` key. +pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, OctetStringRef<'a>, BitStringRef<'a>>; + +/// [`PrivateKeyInfo`] with [`Any`] algorithm parameters, and `Box<[u8]>` key. +#[cfg(feature = "alloc")] +pub type PrivateKeyInfoOwned = PrivateKeyInfo; + +/// [`BitStringLike`] marks object that will act like a BitString. +/// +/// It will allow to get a [`BitStringRef`] that points back to the underlying bytes. +pub trait BitStringLike { + fn as_bit_string(&self) -> BitStringRef<'_>; +} + +impl<'a> BitStringLike for BitStringRef<'a> { + fn as_bit_string(&self) -> BitStringRef<'_> { + BitStringRef::from(self) + } +} + +#[cfg(feature = "alloc")] +mod allocating { + use super::*; + use der::referenced::*; + + impl BitStringLike for BitString { + fn as_bit_string(&self) -> BitStringRef<'_> { + BitStringRef::from(self) + } + } + + impl<'a> RefToOwned<'a> for PrivateKeyInfoRef<'a> { + type Owned = PrivateKeyInfoOwned; + fn ref_to_owned(&self) -> Self::Owned { + PrivateKeyInfoOwned { + algorithm: self.algorithm.ref_to_owned(), + private_key: self.private_key.ref_to_owned(), + public_key: self.public_key.ref_to_owned(), + } + } + } + + impl OwnedToRef for PrivateKeyInfoOwned { + type Borrowed<'a> = PrivateKeyInfoRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + PrivateKeyInfoRef { + algorithm: self.algorithm.owned_to_ref(), + private_key: self.private_key.owned_to_ref(), + public_key: self.public_key.owned_to_ref(), + } + } + } +} diff --git a/pkcs8/src/traits.rs b/pkcs8/src/traits.rs index a38a78e6d..6d110b6e6 100644 --- a/pkcs8/src/traits.rs +++ b/pkcs8/src/traits.rs @@ -1,12 +1,12 @@ //! 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; #[cfg(feature = "encryption")] -use {crate::EncryptedPrivateKeyInfo, rand_core::CryptoRngCore}; +use {crate::EncryptedPrivateKeyInfoRef, rand_core::CryptoRngCore}; #[cfg(feature = "pem")] use { @@ -31,7 +31,7 @@ pub trait DecodePrivateKey: Sized { /// (binary format) and attempt to decrypt it using the provided password. #[cfg(feature = "encryption")] fn from_pkcs8_encrypted_der(bytes: &[u8], password: impl AsRef<[u8]>) -> Result { - let doc = EncryptedPrivateKeyInfo::try_from(bytes)?.decrypt(password)?; + let doc = EncryptedPrivateKeyInfoRef::try_from(bytes)?.decrypt(password)?; Self::from_pkcs8_der(doc.as_bytes()) } @@ -46,7 +46,7 @@ pub trait DecodePrivateKey: Sized { fn from_pkcs8_pem(s: &str) -> Result { // Validate PEM label let label = pem::decode_label(s.as_bytes())?; - PrivateKeyInfo::validate_pem_label(label)?; + PrivateKeyInfoRef::validate_pem_label(label)?; let doc = SecretDocument::from_pem(s)?.1; Self::from_pkcs8_der(doc.as_bytes()) @@ -63,7 +63,7 @@ pub trait DecodePrivateKey: Sized { #[cfg(all(feature = "encryption", feature = "pem"))] fn from_pkcs8_encrypted_pem(s: &str, password: impl AsRef<[u8]>) -> Result { let (label, doc) = SecretDocument::from_pem(s)?; - EncryptedPrivateKeyInfo::validate_pem_label(label)?; + EncryptedPrivateKeyInfoRef::validate_pem_label(label)?; Self::from_pkcs8_encrypted_der(doc.as_bytes(), password) } @@ -78,17 +78,17 @@ pub trait DecodePrivateKey: Sized { #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs8_pem_file(path: impl AsRef) -> Result { let (label, doc) = SecretDocument::read_pem_file(path)?; - PrivateKeyInfo::validate_pem_label(&label)?; + PrivateKeyInfoRef::validate_pem_label(&label)?; Self::from_pkcs8_der(doc.as_bytes()) } } impl DecodePrivateKey for T where - T: for<'a> TryFrom, Error = Error>, + T: for<'a> TryFrom, Error = Error>, { fn from_pkcs8_der(bytes: &[u8]) -> Result { - Self::try_from(PrivateKeyInfo::try_from(bytes)?) + Self::try_from(PrivateKeyInfoRef::try_from(bytes)?) } } @@ -106,14 +106,14 @@ pub trait EncodePrivateKey { rng: &mut impl CryptoRngCore, password: impl AsRef<[u8]>, ) -> Result { - EncryptedPrivateKeyInfo::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes()) + EncryptedPrivateKeyInfoRef::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes()) } /// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`]. #[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 @@ -126,7 +126,7 @@ pub trait EncodePrivateKey { line_ending: LineEnding, ) -> Result> { let doc = self.to_pkcs8_encrypted_der(rng, password)?; - Ok(doc.to_pem(EncryptedPrivateKeyInfo::PEM_LABEL, line_ending)?) + Ok(doc.to_pem(EncryptedPrivateKeyInfoRef::PEM_LABEL, line_ending)?) } /// Write ASN.1 DER-encoded PKCS#8 private key to the given path @@ -139,6 +139,6 @@ pub trait EncodePrivateKey { #[cfg(all(feature = "pem", feature = "std"))] fn write_pkcs8_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs8_der()?; - Ok(doc.write_pem_file(path, PrivateKeyInfo::PEM_LABEL, line_ending)?) + Ok(doc.write_pem_file(path, PrivateKeyInfoRef::PEM_LABEL, line_ending)?) } } diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index cd7ad6b0a..a1560d37c 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -2,8 +2,9 @@ #![cfg(feature = "pkcs5")] +use der::asn1::OctetStringRef; use hex_literal::hex; -use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo, PrivateKeyInfo}; +use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfoRef, PrivateKeyInfoRef}; #[cfg(feature = "alloc")] use der::Encode; @@ -11,6 +12,9 @@ use der::Encode; #[cfg(feature = "pem")] use der::EncodePem; +#[cfg(feature = "encryption")] +use pkcs8::EncryptedPrivateKeyInfoOwned; + /// Ed25519 PKCS#8 private key plaintext encoded as ASN.1 DER #[cfg(feature = "encryption")] const ED25519_DER_PLAINTEXT_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); @@ -101,7 +105,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(), @@ -127,13 +131,16 @@ fn decode_ed25519_encpriv_aes128_pbkdf2_sha1_der() { // $ openssl asn1parse -inform der -in tests/examples/ed25519-encpriv-aes128-sha1.der assert_eq!( pk.encrypted_data, - &hex!("4B4D091548EAC381EE7663B21234CD4FF3C9DF664D713394CACCEA7C9B982BD8F29910FABCA4BF7BE0431FAC5C4D657BE997C1F5BF40E2DA465AC1FCC2E30470") + OctetStringRef::new( + &hex!("4B4D091548EAC381EE7663B21234CD4FF3C9DF664D713394CACCEA7C9B982BD8F29910FABCA4BF7BE0431FAC5C4D657BE997C1F5BF40E2DA465AC1FCC2E30470") + ).unwrap() ); } #[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(), @@ -159,7 +166,9 @@ fn decode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { // $ openssl asn1parse -inform der -in tests/examples/ed25519-encpriv-aes256-sha256.der assert_eq!( pk.encrypted_data, - &hex!("D0CD6C770F4BB87176422305C17401809E226674CE74185D221BFDAA95069890C8882FCE02B05D41BCBF54B035595BCD4154B32593708469B86AACF8815A7B2B") + OctetStringRef::new( + &hex!("D0CD6C770F4BB87176422305C17401809E226674CE74185D221BFDAA95069890C8882FCE02B05D41BCBF54B035595BCD4154B32593708469B86AACF8815A7B2B") + ).unwrap() ); } @@ -167,7 +176,7 @@ fn decode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { #[test] fn decrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { let enc_pk = - EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } @@ -175,7 +184,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); } @@ -183,7 +192,8 @@ fn decrypt_ed25519_der_encpriv_aes256_scrypt() { #[cfg(feature = "encryption")] #[test] fn decrypt_ed25519_der_encpriv_aes128_gcm_scrypt() { - let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES128_GCM_SCRYPT_EXAMPLE).unwrap(); + let enc_pk = + EncryptedPrivateKeyInfoOwned::try_from(ED25519_DER_AES128_GCM_SCRYPT_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } @@ -198,7 +208,7 @@ fn encrypt_ed25519_der_encpriv_aes128_gcm_scrypt() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(scrypt_params, PASSWORD) .unwrap(); @@ -212,7 +222,8 @@ fn encrypt_ed25519_der_encpriv_aes128_gcm_scrypt() { #[cfg(feature = "encryption")] #[test] fn decrypt_ed25519_der_encpriv_aes256_gcm_scrypt() { - let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_GCM_SCRYPT_EXAMPLE).unwrap(); + let enc_pk = + EncryptedPrivateKeyInfoOwned::try_from(ED25519_DER_AES256_GCM_SCRYPT_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } @@ -227,7 +238,7 @@ fn encrypt_ed25519_der_encpriv_aes256_gcm_scrypt() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(scrypt_params, PASSWORD) .unwrap(); @@ -248,7 +259,7 @@ fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { ) .unwrap(); - let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_plaintext = PrivateKeyInfoRef::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); let pk_encrypted = pk_plaintext .encrypt_with_params(pbes2_params, PASSWORD) .unwrap(); @@ -269,7 +280,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(); @@ -280,7 +291,8 @@ fn encrypt_ed25519_der_encpriv_aes256_scrypt() { #[test] #[cfg(feature = "alloc")] fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { - let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + let pk = + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); assert_eq!( ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE, &pk.to_der().unwrap() @@ -290,7 +302,8 @@ fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { #[test] #[cfg(feature = "pem")] fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_pem() { - let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + let pk = + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); assert_eq!( ED25519_PEM_AES256_PBKDF2_SHA256_EXAMPLE, pk.to_pem(Default::default()).unwrap() @@ -300,7 +313,8 @@ fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_pem() { #[test] #[cfg(feature = "3des")] fn decrypt_ed25519_der_encpriv_des3_pbkdf2_sha256() { - let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_DES3_PBKDF2_SHA256_EXAMPLE).unwrap(); + let enc_pk = + EncryptedPrivateKeyInfoRef::try_from(ED25519_DER_DES3_PBKDF2_SHA256_EXAMPLE).unwrap(); let pk = enc_pk.decrypt(PASSWORD).unwrap(); assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); } @@ -308,7 +322,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); } diff --git a/pkcs8/tests/private_key.rs b/pkcs8/tests/private_key.rs index d1dce2b54..5bb4ce605 100644 --- a/pkcs8/tests/private_key.rs +++ b/pkcs8/tests/private_key.rs @@ -1,8 +1,8 @@ //! PKCS#8 private key tests -use der::asn1::ObjectIdentifier; +use der::asn1::{ObjectIdentifier, OctetStringRef}; use hex_literal::hex; -use pkcs8::{PrivateKeyInfo, Version}; +use pkcs8::{PrivateKeyInfoRef, Version}; #[cfg(feature = "alloc")] use der::Encode; @@ -49,7 +49,7 @@ const X25519_PEM_EXAMPLE: &str = include_str!("examples/x25519-priv.pem"); #[test] fn decode_ec_p256_der() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.2.840.10045.2.1".parse().unwrap()); @@ -65,12 +65,12 @@ 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] fn decode_ec_bignp256_der() { - let pk = PrivateKeyInfo::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!( pk.algorithm.oid, @@ -90,7 +90,10 @@ fn decode_ec_bignp256_der() { // $ openssl asn1parse -inform der -in tests/examples/bign256-priv.der assert_eq!( pk.private_key, - &hex!("1F66B5B84B7339674533F0329C74F21834281FED0732429E0C79235FC273E269") + OctetStringRef::new(&hex!( + "1F66B5B84B7339674533F0329C74F21834281FED0732429E0C79235FC273E269" + )) + .unwrap() ) } @@ -98,7 +101,7 @@ fn decode_ec_bignp256_der() { // https://datatracker.ietf.org/doc/html/rfc8410#section-10.3 #[test] fn decode_ed25519_der_v1() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -106,7 +109,7 @@ fn decode_ed25519_der_v1() { // Extracted with: // $ openssl asn1parse -inform der -in tests/examples/ed25519-priv.der assert_eq!( - pk.private_key, + pk.private_key.as_ref(), &hex!("042017ED9C73E9DB649EC189A612831C5FC570238207C1AA9DFBD2C53E3FF5E5EA85")[..] ); } @@ -122,29 +125,29 @@ 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.and_then(|p| p.as_bytes()), Some(&PUB_KEY[..])); } #[test] fn decode_rsa_2048_der() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.2.840.113549.1.1.1".parse().unwrap()); assert!(pk.algorithm.parameters.unwrap().is_null()); // Extracted with: // $ openssl asn1parse -inform der -in tests/examples/rsa2048-priv.der - assert_eq!(pk.private_key, &hex!("308204A30201000282010100B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F0203010001028201007ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C102818100DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D6702818100D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F902818100CE68B7AC1B0D100D636E55488753C5C09843FDB390E2705DF7689457C9BD8D9765E30978617E2EFC8048F4C324206DB86087B654E97BB3D464E7EE3F8CD83FE10436F7DF18E9A963C4E64911D67EDE34042F2E26E3D3A1AD346ADAD6B9B7F67708CB094E62DEE9FF4D5D6669AF988AF2255D1CE8ED317C6A7D8691DA354D12DB02818025F6E5944220286B4DFBBF4235C0EE5843D2198091895120D6CA7B200B826D3ECE738E2E00498FAC0A2A6CA969C7F0C3CA1AB0BC40297132BE7538D7BEDF4CB0EFC6B98EF7DBA54F56AA99AABCE534C49C27947D4678C51C63C78C7CE1687231B4C8EB587AE6EF0480CBAF4FC0173CFD587A7E67AF515FB9B9DE75111839722902818031995406D406207CADEAEA35B38D040C5F8A9A1AE0827E9ED06B153D83B6821935B4B36A82BE9D56C791B58C27271A5793D53A1D657C08997960B1433E5171987F452F144A7C72306D63E1D3FFC0B71B75AB08F2E45A482E988451CBE478E12EB228D07456C924B66F6CED048D853F533E31A68614F1C3CE6D8EC9983CE72AF7")[..]); + assert_eq!(pk.private_key.as_ref(), &hex!("308204A30201000282010100B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F0203010001028201007ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C102818100DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D6702818100D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F902818100CE68B7AC1B0D100D636E55488753C5C09843FDB390E2705DF7689457C9BD8D9765E30978617E2EFC8048F4C324206DB86087B654E97BB3D464E7EE3F8CD83FE10436F7DF18E9A963C4E64911D67EDE34042F2E26E3D3A1AD346ADAD6B9B7F67708CB094E62DEE9FF4D5D6669AF988AF2255D1CE8ED317C6A7D8691DA354D12DB02818025F6E5944220286B4DFBBF4235C0EE5843D2198091895120D6CA7B200B826D3ECE738E2E00498FAC0A2A6CA969C7F0C3CA1AB0BC40297132BE7538D7BEDF4CB0EFC6B98EF7DBA54F56AA99AABCE534C49C27947D4678C51C63C78C7CE1687231B4C8EB587AE6EF0480CBAF4FC0173CFD587A7E67AF515FB9B9DE75111839722902818031995406D406207CADEAEA35B38D040C5F8A9A1AE0827E9ED06B153D83B6821935B4B36A82BE9D56C791B58C27271A5793D53A1D657C08997960B1433E5171987F452F144A7C72306D63E1D3FFC0B71B75AB08F2E45A482E988451CBE478E12EB228D07456C924B66F6CED048D853F533E31A68614F1C3CE6D8EC9983CE72AF7")[..]); } #[test] fn decode_x25519_der() { - let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(X25519_DER_EXAMPLE).unwrap(); assert_eq!(pk.version(), Version::V1); assert_eq!(pk.algorithm.oid, "1.3.101.110".parse().unwrap()); assert_eq!(pk.algorithm.parameters, None); @@ -152,7 +155,7 @@ fn decode_x25519_der() { // Extracted with: // $ openssl asn1parse -inform der -in tests/examples/x25519-priv.der assert_eq!( - pk.private_key, + pk.private_key.as_ref(), &hex!("04207060252933AC6E7A4A9B0EB2632C5A040A87257ADB869A3ECCC3D16B724F2647")[..] ); } @@ -160,7 +163,7 @@ fn decode_x25519_der() { #[test] #[cfg(feature = "alloc")] fn encode_ec_p256_der() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); let pk_encoded = pk.to_der().unwrap(); assert_eq!(EC_P256_DER_EXAMPLE, pk_encoded); } @@ -168,7 +171,7 @@ fn encode_ec_p256_der() { #[test] #[cfg(feature = "alloc")] fn encode_ec_bignp256_der() { - let pk = PrivateKeyInfo::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); let pk_encoded = pk.to_der().unwrap(); assert_eq!(EC_BIGN_P256_DER_EXAMPLE, pk_encoded); } @@ -176,59 +179,59 @@ fn encode_ec_bignp256_der() { #[test] #[cfg(feature = "alloc")] fn encode_ed25519_der_v1() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(ED25519_DER_V1_EXAMPLE, pk.to_der().unwrap()); } #[test] #[cfg(all(feature = "alloc", feature = "subtle"))] fn encode_ed25519_der_v2() { - let private_key = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + let private_key = PrivateKeyInfoRef::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); let private_der = private_key.to_der().unwrap(); assert_eq!( private_key, - PrivateKeyInfo::try_from(private_der.as_ref()).unwrap() + PrivateKeyInfoRef::try_from(private_der.as_ref()).unwrap() ); } #[test] #[cfg(feature = "alloc")] fn encode_rsa_2048_der() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(RSA_2048_DER_EXAMPLE, &pk.to_der().unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_ec_p256_pem() { - let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap(); assert_eq!(EC_P256_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_ec_bignp256_pem() { - let pk = PrivateKeyInfo::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(EC_BIGN_P256_DER_EXAMPLE).unwrap(); assert_eq!(EC_BIGN_P256_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_ed25519_pem() { - let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); assert_eq!(ED25519_PEM_V1_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_rsa_2048_pem() { - let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(RSA_2048_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } #[test] #[cfg(feature = "pem")] fn encode_x25519_pem() { - let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); + let pk = PrivateKeyInfoRef::try_from(X25519_DER_EXAMPLE).unwrap(); assert_eq!(X25519_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); } diff --git a/pkcs8/tests/traits.rs b/pkcs8/tests/traits.rs index 4a603bb94..c9e63d124 100644 --- a/pkcs8/tests/traits.rs +++ b/pkcs8/tests/traits.rs @@ -3,7 +3,7 @@ #![cfg(any(feature = "pem", feature = "std"))] use der::Encode; -use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfo, Result, SecretDocument}; +use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfoRef, Result, SecretDocument}; #[cfg(feature = "pem")] use pkcs8::der::pem::LineEnding; @@ -14,7 +14,7 @@ use tempfile::tempdir; #[cfg(all(feature = "pem", feature = "std"))] use std::fs; -/// Ed25519 `PrivateKeyInfo` encoded as ASN.1 DER +/// Ed25519 `PrivateKeyInfoRef` encoded as ASN.1 DER const ED25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); /// Ed25519 private key encoded as PEM @@ -36,10 +36,10 @@ impl EncodePrivateKey for MockKey { } } -impl TryFrom> for MockKey { +impl TryFrom> for MockKey { type Error = Error; - fn try_from(pkcs8: PrivateKeyInfo<'_>) -> Result { + fn try_from(pkcs8: PrivateKeyInfoRef<'_>) -> Result { Ok(MockKey(pkcs8.to_der()?)) } } diff --git a/sec1/src/traits.rs b/sec1/src/traits.rs index ce72ad3b5..212a33269 100644 --- a/sec1/src/traits.rs +++ b/sec1/src/traits.rs @@ -11,7 +11,7 @@ use {crate::LineEnding, alloc::string::String, der::pem::PemLabel}; #[cfg(feature = "pkcs8")] use { crate::{EcPrivateKey, ALGORITHM_OID}, - der::Decode, + der::{asn1::OctetStringRef, Decode}, }; #[cfg(feature = "std")] @@ -88,7 +88,7 @@ pub trait EncodeEcPrivateKey { #[cfg(feature = "pkcs8")] impl DecodeEcPrivateKey for T where - T: for<'a> TryFrom, Error = pkcs8::Error>, + T: for<'a> TryFrom, Error = pkcs8::Error>, { fn from_sec1_der(private_key: &[u8]) -> Result { let params_oid = EcPrivateKey::from_der(private_key)? @@ -100,7 +100,9 @@ where parameters: params_oid.as_ref().map(Into::into), }; - Ok(Self::try_from(pkcs8::PrivateKeyInfo { + let private_key = OctetStringRef::new(private_key)?; + + Ok(Self::try_from(pkcs8::PrivateKeyInfoRef { algorithm, private_key, public_key: None, @@ -112,10 +114,10 @@ where impl EncodeEcPrivateKey for T { fn to_sec1_der(&self) -> Result { let doc = self.to_pkcs8_der()?; - let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(doc.as_bytes())?; + let pkcs8_key = pkcs8::PrivateKeyInfoRef::from_der(doc.as_bytes())?; pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; - let mut pkcs1_key = EcPrivateKey::from_der(pkcs8_key.private_key)?; + let mut pkcs1_key = EcPrivateKey::from_der(pkcs8_key.private_key.as_bytes())?; pkcs1_key.parameters = Some(pkcs8_key.algorithm.parameters_oid()?.into()); pkcs1_key.try_into() }