Skip to content

Commit 6877a3e

Browse files
authored
pkcs8: provide PrivateKeyInfoRef/PrivateKeyInfoOwned (#1483)
This makes the `PrivateKeyInfo` generic over its backing storage, and this provides two versions of it, namely `PrivateKeyInfoRef` and `PrivateKeyInfoOwned` respectively borrowing the value and owning the storage of the value. Signed-off-by: Arthur Gautier <[email protected]>
1 parent 85b389d commit 6877a3e

14 files changed

+358
-180
lines changed

Cargo.lock

+7-19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+6-1
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,9 @@ x509-cert = { path = "./x509-cert" }
6060
x509-ocsp = { path = "./x509-ocsp" }
6161

6262
# Temp patches to external crates
63-
ecdsa = { git = "https://github.com/RustCrypto/signatures" }
63+
# https://github.com/RustCrypto/signatures/pull/851
64+
ecdsa = { git = "https://github.com/baloo/signatures", branch = "baloo/pkcs8/api-change" }
65+
# https://github.com/RustCrypto/RSA/pull/446
66+
rsa = { git = "https://github.com/baloo/RSA", branch = "baloo/pkcs8/api-changes" }
67+
# https://github.com/RustCrypto/traits/pull/1650
68+
elliptic-curve = { git = "https://github.com/baloo/traits.git", branch ="baloo/elliptic-curve/pkcs8-API-break" }

cms/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ zeroize = { version = "1.8.1", optional = true }
3535
getrandom = "0.2"
3636
hex-literal = "0.4"
3737
pem-rfc7468 = "1.0.0-rc.1"
38-
pkcs5 = "=0.8.0-rc.0"
38+
pkcs5 = "0.8.0-rc.1"
3939
rand = "0.8.5"
4040
rsa = { version = "=0.10.0-pre.2", features = ["sha2"] }
4141
ecdsa = { version = "=0.17.0-pre.7", features = ["digest", "pem"] }

pkcs1/src/private_key.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ pub(crate) mod other_prime_info;
66
use crate::{Error, Result, RsaPublicKey, Version};
77
use core::fmt;
88
use der::{
9-
asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag,
10-
Writer,
9+
asn1::{OctetStringRef, UintRef},
10+
Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer,
1111
};
1212

1313
#[cfg(feature = "alloc")]
@@ -172,6 +172,14 @@ impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> {
172172
}
173173
}
174174

175+
impl<'a> TryFrom<OctetStringRef<'a>> for RsaPrivateKey<'a> {
176+
type Error = Error;
177+
178+
fn try_from(bytes: OctetStringRef<'a>) -> Result<Self> {
179+
Ok(Self::from_der(bytes.as_bytes())?)
180+
}
181+
}
182+
175183
impl fmt::Debug for RsaPrivateKey<'_> {
176184
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177185
f.debug_struct("RsaPrivateKey")

pkcs1/src/traits.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use {
1515
#[cfg(feature = "pkcs8")]
1616
use {
1717
crate::{ALGORITHM_ID, ALGORITHM_OID},
18-
der::asn1::BitStringRef,
18+
der::asn1::{BitStringRef, OctetStringRef},
1919
};
2020

2121
#[cfg(feature = "std")]
@@ -157,10 +157,11 @@ pub trait EncodeRsaPublicKey {
157157
#[cfg(feature = "pkcs8")]
158158
impl<T> DecodeRsaPrivateKey for T
159159
where
160-
T: for<'a> TryFrom<pkcs8::PrivateKeyInfo<'a>, Error = pkcs8::Error>,
160+
T: for<'a> TryFrom<pkcs8::PrivateKeyInfoRef<'a>, Error = pkcs8::Error>,
161161
{
162162
fn from_pkcs1_der(private_key: &[u8]) -> Result<Self> {
163-
Ok(Self::try_from(pkcs8::PrivateKeyInfo {
163+
let private_key = OctetStringRef::new(private_key)?;
164+
Ok(Self::try_from(pkcs8::PrivateKeyInfoRef {
164165
algorithm: ALGORITHM_ID,
165166
private_key,
166167
public_key: None,
@@ -185,9 +186,9 @@ where
185186
impl<T: pkcs8::EncodePrivateKey> EncodeRsaPrivateKey for T {
186187
fn to_pkcs1_der(&self) -> Result<SecretDocument> {
187188
let pkcs8_doc = self.to_pkcs8_der()?;
188-
let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(pkcs8_doc.as_bytes())?;
189+
let pkcs8_key = pkcs8::PrivateKeyInfoRef::from_der(pkcs8_doc.as_bytes())?;
189190
pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?;
190-
RsaPrivateKey::from_der(pkcs8_key.private_key)?.try_into()
191+
RsaPrivateKey::from_der(pkcs8_key.private_key.as_bytes())?.try_into()
191192
}
192193
}
193194

pkcs12/tests/cert_tests.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use pkcs8::{
1313
self,
1414
pbes2::{AES_256_CBC_OID, HMAC_WITH_SHA256_OID, PBES2_OID, PBKDF2_OID},
1515
},
16-
EncryptedPrivateKeyInfo,
16+
EncryptedPrivateKeyInfoRef,
1717
};
1818
use spki::AlgorithmIdentifierOwned;
1919

@@ -242,9 +242,9 @@ fn decode_sample_pfx() {
242242
for safe_bag in safe_bags {
243243
match safe_bag.bag_id {
244244
pkcs12::PKCS_12_PKCS8_KEY_BAG_OID => {
245-
let cs: ContextSpecific<EncryptedPrivateKeyInfo> =
245+
let cs: ContextSpecific<EncryptedPrivateKeyInfoRef<'_>> =
246246
ContextSpecific::from_der(&safe_bag.bag_value).unwrap();
247-
let mut ciphertext = cs.value.encrypted_data.to_vec();
247+
let mut ciphertext = cs.value.encrypted_data.as_bytes().to_vec();
248248
let plaintext = cs
249249
.value
250250
.encryption_algorithm
@@ -628,9 +628,9 @@ fn decode_sample_pfx2() {
628628
for safe_bag in safe_bags {
629629
match safe_bag.bag_id {
630630
pkcs12::PKCS_12_PKCS8_KEY_BAG_OID => {
631-
let cs: ContextSpecific<EncryptedPrivateKeyInfo> =
631+
let cs: ContextSpecific<EncryptedPrivateKeyInfoRef<'_>> =
632632
ContextSpecific::from_der(&safe_bag.bag_value).unwrap();
633-
let mut ciphertext = cs.value.encrypted_data.to_vec();
633+
let mut ciphertext = cs.value.encrypted_data.as_bytes().to_vec();
634634
let plaintext = cs
635635
.value
636636
.encryption_algorithm

pkcs8/src/encrypted_private_key_info.rs

+53-27
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
use crate::{Error, Result};
44
use core::fmt;
55
use der::{
6-
asn1::OctetStringRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader,
7-
Sequence, Writer,
6+
asn1::OctetStringRef, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length,
7+
Reader, Sequence, Writer,
88
};
99
use pkcs5::EncryptionScheme;
1010

1111
#[cfg(feature = "alloc")]
12-
use der::SecretDocument;
12+
use der::{asn1::OctetString, SecretDocument};
1313

1414
#[cfg(feature = "encryption")]
1515
use {pkcs5::pbes2, rand_core::CryptoRngCore};
@@ -37,23 +37,27 @@ use der::pem::PemLabel;
3737
///
3838
/// [RFC 5208 Section 6]: https://tools.ietf.org/html/rfc5208#section-6
3939
#[derive(Clone, Eq, PartialEq)]
40-
pub struct EncryptedPrivateKeyInfo<'a> {
40+
pub struct EncryptedPrivateKeyInfo<Data> {
4141
/// Algorithm identifier describing a password-based symmetric encryption
4242
/// scheme used to encrypt the `encrypted_data` field.
4343
pub encryption_algorithm: EncryptionScheme,
4444

4545
/// Private key data
46-
pub encrypted_data: &'a [u8],
46+
pub encrypted_data: Data,
4747
}
4848

49-
impl<'a> EncryptedPrivateKeyInfo<'a> {
49+
impl<'a, Data> EncryptedPrivateKeyInfo<Data>
50+
where
51+
Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a,
52+
Data: AsRef<[u8]>,
53+
{
5054
/// Attempt to decrypt this encrypted private key using the provided
5155
/// password to derive an encryption key.
5256
#[cfg(feature = "encryption")]
5357
pub fn decrypt(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument> {
5458
Ok(self
5559
.encryption_algorithm
56-
.decrypt(password, self.encrypted_data)?
60+
.decrypt(password, self.encrypted_data.as_ref())?
5761
.try_into()?)
5862
}
5963

@@ -66,7 +70,7 @@ impl<'a> EncryptedPrivateKeyInfo<'a> {
6670
doc: &[u8],
6771
) -> Result<SecretDocument> {
6872
let pbes2_params = pbes2::Parameters::recommended(rng);
69-
EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, doc)
73+
EncryptedPrivateKeyInfoOwned::encrypt_with(pbes2_params, password, doc)
7074
}
7175

7276
/// Encrypt this private key using a symmetric encryption key derived
@@ -78,55 +82,64 @@ impl<'a> EncryptedPrivateKeyInfo<'a> {
7882
doc: &[u8],
7983
) -> Result<SecretDocument> {
8084
let encrypted_data = pbes2_params.encrypt(password, doc)?;
85+
let encrypted_data = OctetStringRef::new(&encrypted_data)?;
8186

8287
EncryptedPrivateKeyInfo {
8388
encryption_algorithm: pbes2_params.into(),
84-
encrypted_data: &encrypted_data,
89+
encrypted_data,
8590
}
8691
.try_into()
8792
}
8893
}
8994

90-
impl<'a> DecodeValue<'a> for EncryptedPrivateKeyInfo<'a> {
95+
impl<'a, Data> DecodeValue<'a> for EncryptedPrivateKeyInfo<Data>
96+
where
97+
Data: DecodeValue<'a, Error = der::Error> + FixedTag + 'a,
98+
{
9199
type Error = der::Error;
92100

93-
fn decode_value<R: Reader<'a>>(
94-
reader: &mut R,
95-
header: Header,
96-
) -> der::Result<EncryptedPrivateKeyInfo<'a>> {
101+
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
97102
reader.read_nested(header.length, |reader| {
98103
Ok(Self {
99104
encryption_algorithm: reader.decode()?,
100-
encrypted_data: OctetStringRef::decode(reader)?.as_bytes(),
105+
encrypted_data: reader.decode()?,
101106
})
102107
})
103108
}
104109
}
105110

106-
impl EncodeValue for EncryptedPrivateKeyInfo<'_> {
111+
impl<Data> EncodeValue for EncryptedPrivateKeyInfo<Data>
112+
where
113+
Data: EncodeValue + FixedTag,
114+
{
107115
fn value_len(&self) -> der::Result<Length> {
108-
self.encryption_algorithm.encoded_len()?
109-
+ OctetStringRef::new(self.encrypted_data)?.encoded_len()?
116+
self.encryption_algorithm.encoded_len()? + self.encrypted_data.encoded_len()?
110117
}
111118

112119
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
113120
self.encryption_algorithm.encode(writer)?;
114-
OctetStringRef::new(self.encrypted_data)?.encode(writer)?;
121+
self.encrypted_data.encode(writer)?;
115122
Ok(())
116123
}
117124
}
118125

119-
impl<'a> Sequence<'a> for EncryptedPrivateKeyInfo<'a> {}
126+
impl<'a, Data> Sequence<'a> for EncryptedPrivateKeyInfo<Data> where
127+
Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a
128+
{
129+
}
120130

121-
impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> {
131+
impl<'a, Data> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<Data>
132+
where
133+
Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a,
134+
{
122135
type Error = Error;
123136

124137
fn try_from(bytes: &'a [u8]) -> Result<Self> {
125138
Ok(Self::from_der(bytes)?)
126139
}
127140
}
128141

129-
impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> {
142+
impl<Data> fmt::Debug for EncryptedPrivateKeyInfo<Data> {
130143
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131144
f.debug_struct("EncryptedPrivateKeyInfo")
132145
.field("encryption_algorithm", &self.encryption_algorithm)
@@ -135,24 +148,37 @@ impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> {
135148
}
136149

137150
#[cfg(feature = "alloc")]
138-
impl TryFrom<EncryptedPrivateKeyInfo<'_>> for SecretDocument {
151+
impl<'a, Data> TryFrom<EncryptedPrivateKeyInfo<Data>> for SecretDocument
152+
where
153+
Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a,
154+
{
139155
type Error = Error;
140156

141-
fn try_from(encrypted_private_key: EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument> {
157+
fn try_from(encrypted_private_key: EncryptedPrivateKeyInfo<Data>) -> Result<SecretDocument> {
142158
SecretDocument::try_from(&encrypted_private_key)
143159
}
144160
}
145161

146162
#[cfg(feature = "alloc")]
147-
impl TryFrom<&EncryptedPrivateKeyInfo<'_>> for SecretDocument {
163+
impl<'a, Data> TryFrom<&EncryptedPrivateKeyInfo<Data>> for SecretDocument
164+
where
165+
Data: DecodeValue<'a, Error = der::Error> + EncodeValue + FixedTag + 'a,
166+
{
148167
type Error = Error;
149168

150-
fn try_from(encrypted_private_key: &EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument> {
169+
fn try_from(encrypted_private_key: &EncryptedPrivateKeyInfo<Data>) -> Result<SecretDocument> {
151170
Ok(Self::encode_msg(encrypted_private_key)?)
152171
}
153172
}
154173

155174
#[cfg(feature = "pem")]
156-
impl PemLabel for EncryptedPrivateKeyInfo<'_> {
175+
impl<Data> PemLabel for EncryptedPrivateKeyInfo<Data> {
157176
const PEM_LABEL: &'static str = "ENCRYPTED PRIVATE KEY";
158177
}
178+
179+
/// [`EncryptedPrivateKeyInfo`] with [`OctetStringRef`] encrypted data.
180+
pub type EncryptedPrivateKeyInfoRef<'a> = EncryptedPrivateKeyInfo<OctetStringRef<'a>>;
181+
182+
#[cfg(feature = "alloc")]
183+
/// [`EncryptedPrivateKeyInfo`] with [`OctetString`] encrypted data.
184+
pub type EncryptedPrivateKeyInfoOwned = EncryptedPrivateKeyInfo<OctetString>;

0 commit comments

Comments
 (0)