1 //! PKCS#8 `PrivateKeyInfo`.
2 
3 use crate::{AlgorithmIdentifierRef, Error, Result, Version};
4 use core::fmt;
5 use der::{
6     asn1::{AnyRef, BitStringRef, ContextSpecific, OctetStringRef},
7     Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, TagMode, TagNumber,
8     Writer,
9 };
10 
11 #[cfg(feature = "alloc")]
12 use der::SecretDocument;
13 
14 #[cfg(feature = "encryption")]
15 use {
16     crate::EncryptedPrivateKeyInfo,
17     der::zeroize::Zeroizing,
18     pkcs5::pbes2,
19     rand_core::{CryptoRng, RngCore},
20 };
21 
22 #[cfg(feature = "pem")]
23 use der::pem::PemLabel;
24 
25 #[cfg(feature = "subtle")]
26 use subtle::{Choice, ConstantTimeEq};
27 
28 /// Context-specific tag number for the public key.
29 const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1;
30 
31 /// PKCS#8 `PrivateKeyInfo`.
32 ///
33 /// ASN.1 structure containing an `AlgorithmIdentifier`, private key
34 /// data in an algorithm specific format, and optional attributes
35 /// (ignored by this implementation).
36 ///
37 /// Supports PKCS#8 v1 as described in [RFC 5208] and PKCS#8 v2 as described
38 /// in [RFC 5958]. PKCS#8 v2 keys include an additional public key field.
39 ///
40 /// # PKCS#8 v1 `PrivateKeyInfo`
41 ///
42 /// Described in [RFC 5208 Section 5]:
43 ///
44 /// ```text
45 /// PrivateKeyInfo ::= SEQUENCE {
46 ///         version                   Version,
47 ///         privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
48 ///         privateKey                PrivateKey,
49 ///         attributes           [0]  IMPLICIT Attributes OPTIONAL }
50 ///
51 /// Version ::= INTEGER
52 ///
53 /// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
54 ///
55 /// PrivateKey ::= OCTET STRING
56 ///
57 /// Attributes ::= SET OF Attribute
58 /// ```
59 ///
60 /// # PKCS#8 v2 `OneAsymmetricKey`
61 ///
62 /// PKCS#8 `OneAsymmetricKey` as described in [RFC 5958 Section 2]:
63 ///
64 /// ```text
65 /// PrivateKeyInfo ::= OneAsymmetricKey
66 ///
67 /// OneAsymmetricKey ::= SEQUENCE {
68 ///     version                   Version,
69 ///     privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
70 ///     privateKey                PrivateKey,
71 ///     attributes            [0] Attributes OPTIONAL,
72 ///     ...,
73 ///     [[2: publicKey        [1] PublicKey OPTIONAL ]],
74 ///     ...
75 ///   }
76 ///
77 /// Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2)
78 ///
79 /// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
80 ///
81 /// PrivateKey ::= OCTET STRING
82 ///
83 /// Attributes ::= SET OF Attribute
84 ///
85 /// PublicKey ::= BIT STRING
86 /// ```
87 ///
88 /// [RFC 5208]: https://tools.ietf.org/html/rfc5208
89 /// [RFC 5958]: https://datatracker.ietf.org/doc/html/rfc5958
90 /// [RFC 5208 Section 5]: https://tools.ietf.org/html/rfc5208#section-5
91 /// [RFC 5958 Section 2]: https://datatracker.ietf.org/doc/html/rfc5958#section-2
92 #[derive(Clone)]
93 pub struct PrivateKeyInfo<'a> {
94     /// X.509 `AlgorithmIdentifier` for the private key type.
95     pub algorithm: AlgorithmIdentifierRef<'a>,
96 
97     /// Private key data.
98     pub private_key: &'a [u8],
99 
100     /// Public key data, optionally available if version is V2.
101     pub public_key: Option<&'a [u8]>,
102 }
103 
104 impl<'a> PrivateKeyInfo<'a> {
105     /// Create a new PKCS#8 [`PrivateKeyInfo`] message.
106     ///
107     /// This is a helper method which initializes `attributes` and `public_key`
108     /// to `None`, helpful if you aren't using those.
new(algorithm: AlgorithmIdentifierRef<'a>, private_key: &'a [u8]) -> Self109     pub fn new(algorithm: AlgorithmIdentifierRef<'a>, private_key: &'a [u8]) -> Self {
110         Self {
111             algorithm,
112             private_key,
113             public_key: None,
114         }
115     }
116 
117     /// Get the PKCS#8 [`Version`] for this structure.
118     ///
119     /// [`Version::V1`] if `public_key` is `None`, [`Version::V2`] if `Some`.
version(&self) -> Version120     pub fn version(&self) -> Version {
121         if self.public_key.is_some() {
122             Version::V2
123         } else {
124             Version::V1
125         }
126     }
127 
128     /// Encrypt this private key using a symmetric encryption key derived
129     /// from the provided password.
130     ///
131     /// Uses the following algorithms for encryption:
132     /// - PBKDF: scrypt with default parameters:
133     ///   - log₂(N): 15
134     ///   - r: 8
135     ///   - p: 1
136     /// - Cipher: AES-256-CBC (best available option for PKCS#5 encryption)
137     #[cfg(feature = "encryption")]
encrypt( &self, rng: impl CryptoRng + RngCore, password: impl AsRef<[u8]>, ) -> Result<SecretDocument>138     pub fn encrypt(
139         &self,
140         rng: impl CryptoRng + RngCore,
141         password: impl AsRef<[u8]>,
142     ) -> Result<SecretDocument> {
143         let der = Zeroizing::new(self.to_der()?);
144         EncryptedPrivateKeyInfo::encrypt(rng, password, der.as_ref())
145     }
146 
147     /// Encrypt this private key using a symmetric encryption key derived
148     /// from the provided password and [`pbes2::Parameters`].
149     #[cfg(feature = "encryption")]
encrypt_with_params( &self, pbes2_params: pbes2::Parameters<'_>, password: impl AsRef<[u8]>, ) -> Result<SecretDocument>150     pub fn encrypt_with_params(
151         &self,
152         pbes2_params: pbes2::Parameters<'_>,
153         password: impl AsRef<[u8]>,
154     ) -> Result<SecretDocument> {
155         let der = Zeroizing::new(self.to_der()?);
156         EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, der.as_ref())
157     }
158 
159     /// Get a `BIT STRING` representation of the public key, if present.
public_key_bit_string(&self) -> der::Result<Option<ContextSpecific<BitStringRef<'a>>>>160     fn public_key_bit_string(&self) -> der::Result<Option<ContextSpecific<BitStringRef<'a>>>> {
161         self.public_key
162             .map(|pk| {
163                 BitStringRef::from_bytes(pk).map(|value| ContextSpecific {
164                     tag_number: PUBLIC_KEY_TAG,
165                     tag_mode: TagMode::Implicit,
166                     value,
167                 })
168             })
169             .transpose()
170     }
171 }
172 
173 impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> {
decode_value<R: Reader<'a>>( reader: &mut R, header: Header, ) -> der::Result<PrivateKeyInfo<'a>>174     fn decode_value<R: Reader<'a>>(
175         reader: &mut R,
176         header: Header,
177     ) -> der::Result<PrivateKeyInfo<'a>> {
178         reader.read_nested(header.length, |reader| {
179             // Parse and validate `version` INTEGER.
180             let version = Version::decode(reader)?;
181             let algorithm = reader.decode()?;
182             let private_key = OctetStringRef::decode(reader)?.into();
183             let public_key = reader
184                 .context_specific::<BitStringRef<'_>>(PUBLIC_KEY_TAG, TagMode::Implicit)?
185                 .map(|bs| {
186                     bs.as_bytes()
187                         .ok_or_else(|| der::Tag::BitString.value_error())
188                 })
189                 .transpose()?;
190 
191             if version.has_public_key() != public_key.is_some() {
192                 return Err(reader.error(
193                     der::Tag::ContextSpecific {
194                         constructed: true,
195                         number: PUBLIC_KEY_TAG,
196                     }
197                     .value_error()
198                     .kind(),
199                 ));
200             }
201 
202             // Ignore any remaining extension fields
203             while !reader.is_finished() {
204                 reader.decode::<ContextSpecific<AnyRef<'_>>>()?;
205             }
206 
207             Ok(Self {
208                 algorithm,
209                 private_key,
210                 public_key,
211             })
212         })
213     }
214 }
215 
216 impl EncodeValue for PrivateKeyInfo<'_> {
value_len(&self) -> der::Result<Length>217     fn value_len(&self) -> der::Result<Length> {
218         self.version().encoded_len()?
219             + self.algorithm.encoded_len()?
220             + OctetStringRef::new(self.private_key)?.encoded_len()?
221             + self.public_key_bit_string()?.encoded_len()?
222     }
223 
encode_value(&self, writer: &mut impl Writer) -> der::Result<()>224     fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
225         self.version().encode(writer)?;
226         self.algorithm.encode(writer)?;
227         OctetStringRef::new(self.private_key)?.encode(writer)?;
228         self.public_key_bit_string()?.encode(writer)?;
229         Ok(())
230     }
231 }
232 
233 impl<'a> Sequence<'a> for PrivateKeyInfo<'a> {}
234 
235 impl<'a> TryFrom<&'a [u8]> for PrivateKeyInfo<'a> {
236     type Error = Error;
237 
try_from(bytes: &'a [u8]) -> Result<Self>238     fn try_from(bytes: &'a [u8]) -> Result<Self> {
239         Ok(Self::from_der(bytes)?)
240     }
241 }
242 
243 impl<'a> fmt::Debug for PrivateKeyInfo<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result244     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245         f.debug_struct("PrivateKeyInfo")
246             .field("version", &self.version())
247             .field("algorithm", &self.algorithm)
248             .field("public_key", &self.public_key)
249             .finish_non_exhaustive()
250     }
251 }
252 
253 #[cfg(feature = "alloc")]
254 impl TryFrom<PrivateKeyInfo<'_>> for SecretDocument {
255     type Error = Error;
256 
try_from(private_key: PrivateKeyInfo<'_>) -> Result<SecretDocument>257     fn try_from(private_key: PrivateKeyInfo<'_>) -> Result<SecretDocument> {
258         SecretDocument::try_from(&private_key)
259     }
260 }
261 
262 #[cfg(feature = "alloc")]
263 impl TryFrom<&PrivateKeyInfo<'_>> for SecretDocument {
264     type Error = Error;
265 
try_from(private_key: &PrivateKeyInfo<'_>) -> Result<SecretDocument>266     fn try_from(private_key: &PrivateKeyInfo<'_>) -> Result<SecretDocument> {
267         Ok(Self::encode_msg(private_key)?)
268     }
269 }
270 
271 #[cfg(feature = "pem")]
272 impl PemLabel for PrivateKeyInfo<'_> {
273     const PEM_LABEL: &'static str = "PRIVATE KEY";
274 }
275 
276 #[cfg(feature = "subtle")]
277 impl<'a> ConstantTimeEq for PrivateKeyInfo<'a> {
ct_eq(&self, other: &Self) -> Choice278     fn ct_eq(&self, other: &Self) -> Choice {
279         // NOTE: public fields are not compared in constant time
280         let public_fields_eq =
281             self.algorithm == other.algorithm && self.public_key == other.public_key;
282 
283         self.private_key.ct_eq(other.private_key) & Choice::from(public_fields_eq as u8)
284     }
285 }
286 
287 #[cfg(feature = "subtle")]
288 impl<'a> Eq for PrivateKeyInfo<'a> {}
289 
290 #[cfg(feature = "subtle")]
291 impl<'a> PartialEq for PrivateKeyInfo<'a> {
eq(&self, other: &Self) -> bool292     fn eq(&self, other: &Self) -> bool {
293         self.ct_eq(other).into()
294     }
295 }
296