• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Traits for parsing objects from PKCS#8 encoded documents
2 
3 use crate::{Error, PrivateKeyInfo, Result};
4 
5 #[cfg(feature = "alloc")]
6 use der::SecretDocument;
7 
8 #[cfg(feature = "encryption")]
9 use {
10     crate::EncryptedPrivateKeyInfo,
11     rand_core::{CryptoRng, RngCore},
12 };
13 
14 #[cfg(feature = "pem")]
15 use {crate::LineEnding, alloc::string::String, der::zeroize::Zeroizing};
16 
17 #[cfg(feature = "pem")]
18 use der::pem::PemLabel;
19 
20 #[cfg(feature = "std")]
21 use std::path::Path;
22 
23 /// Parse a private key object from a PKCS#8 encoded document.
24 pub trait DecodePrivateKey: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error> + Sized {
25     /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data
26     /// (binary format).
from_pkcs8_der(bytes: &[u8]) -> Result<Self>27     fn from_pkcs8_der(bytes: &[u8]) -> Result<Self> {
28         Self::try_from(PrivateKeyInfo::try_from(bytes)?)
29     }
30 
31     /// Deserialize encrypted PKCS#8 private key from ASN.1 DER-encoded data
32     /// (binary format) and attempt to decrypt it using the provided password.
33     #[cfg(feature = "encryption")]
34     #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
from_pkcs8_encrypted_der(bytes: &[u8], password: impl AsRef<[u8]>) -> Result<Self>35     fn from_pkcs8_encrypted_der(bytes: &[u8], password: impl AsRef<[u8]>) -> Result<Self> {
36         let doc = EncryptedPrivateKeyInfo::try_from(bytes)?.decrypt(password)?;
37         Self::from_pkcs8_der(doc.as_bytes())
38     }
39 
40     /// Deserialize PKCS#8-encoded private key from PEM.
41     ///
42     /// Keys in this format begin with the following delimiter:
43     ///
44     /// ```text
45     /// -----BEGIN PRIVATE KEY-----
46     /// ```
47     #[cfg(feature = "pem")]
48     #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
from_pkcs8_pem(s: &str) -> Result<Self>49     fn from_pkcs8_pem(s: &str) -> Result<Self> {
50         let (label, doc) = SecretDocument::from_pem(s)?;
51         PrivateKeyInfo::validate_pem_label(label)?;
52         Self::from_pkcs8_der(doc.as_bytes())
53     }
54 
55     /// Deserialize encrypted PKCS#8-encoded private key from PEM and attempt
56     /// to decrypt it using the provided password.
57     ///
58     /// Keys in this format begin with the following delimiter:
59     ///
60     /// ```text
61     /// -----BEGIN ENCRYPTED PRIVATE KEY-----
62     /// ```
63     #[cfg(all(feature = "encryption", feature = "pem"))]
64     #[cfg_attr(docsrs, doc(cfg(all(feature = "encryption", feature = "pem"))))]
from_pkcs8_encrypted_pem(s: &str, password: impl AsRef<[u8]>) -> Result<Self>65     fn from_pkcs8_encrypted_pem(s: &str, password: impl AsRef<[u8]>) -> Result<Self> {
66         let (label, doc) = SecretDocument::from_pem(s)?;
67         EncryptedPrivateKeyInfo::validate_pem_label(label)?;
68         Self::from_pkcs8_encrypted_der(doc.as_bytes(), password)
69     }
70 
71     /// Load PKCS#8 private key from an ASN.1 DER-encoded file on the local
72     /// filesystem (binary format).
73     #[cfg(feature = "std")]
74     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read_pkcs8_der_file(path: impl AsRef<Path>) -> Result<Self>75     fn read_pkcs8_der_file(path: impl AsRef<Path>) -> Result<Self> {
76         Self::from_pkcs8_der(SecretDocument::read_der_file(path)?.as_bytes())
77     }
78 
79     /// Load PKCS#8 private key from a PEM-encoded file on the local filesystem.
80     #[cfg(all(feature = "pem", feature = "std"))]
81     #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
82     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read_pkcs8_pem_file(path: impl AsRef<Path>) -> Result<Self>83     fn read_pkcs8_pem_file(path: impl AsRef<Path>) -> Result<Self> {
84         let (label, doc) = SecretDocument::read_pem_file(path)?;
85         PrivateKeyInfo::validate_pem_label(&label)?;
86         Self::from_pkcs8_der(doc.as_bytes())
87     }
88 }
89 
90 /// Serialize a private key object to a PKCS#8 encoded document.
91 #[cfg(feature = "alloc")]
92 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
93 pub trait EncodePrivateKey {
94     /// Serialize a [`SecretDocument`] containing a PKCS#8-encoded private key.
to_pkcs8_der(&self) -> Result<SecretDocument>95     fn to_pkcs8_der(&self) -> Result<SecretDocument>;
96 
97     /// Create an [`SecretDocument`] containing the ciphertext of
98     /// a PKCS#8 encoded private key encrypted under the given `password`.
99     #[cfg(feature = "encryption")]
100     #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
to_pkcs8_encrypted_der( &self, rng: impl CryptoRng + RngCore, password: impl AsRef<[u8]>, ) -> Result<SecretDocument>101     fn to_pkcs8_encrypted_der(
102         &self,
103         rng: impl CryptoRng + RngCore,
104         password: impl AsRef<[u8]>,
105     ) -> Result<SecretDocument> {
106         EncryptedPrivateKeyInfo::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes())
107     }
108 
109     /// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`].
110     #[cfg(feature = "pem")]
111     #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
to_pkcs8_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>>112     fn to_pkcs8_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>> {
113         let doc = self.to_pkcs8_der()?;
114         Ok(doc.to_pem(PrivateKeyInfo::PEM_LABEL, line_ending)?)
115     }
116 
117     /// Serialize this private key as an encrypted PEM-encoded PKCS#8 private
118     /// key using the `provided` to derive an encryption key.
119     #[cfg(all(feature = "encryption", feature = "pem"))]
120     #[cfg_attr(docsrs, doc(cfg(all(feature = "encryption", feature = "pem"))))]
to_pkcs8_encrypted_pem( &self, rng: impl CryptoRng + RngCore, password: impl AsRef<[u8]>, line_ending: LineEnding, ) -> Result<Zeroizing<String>>121     fn to_pkcs8_encrypted_pem(
122         &self,
123         rng: impl CryptoRng + RngCore,
124         password: impl AsRef<[u8]>,
125         line_ending: LineEnding,
126     ) -> Result<Zeroizing<String>> {
127         let doc = self.to_pkcs8_encrypted_der(rng, password)?;
128         Ok(doc.to_pem(EncryptedPrivateKeyInfo::PEM_LABEL, line_ending)?)
129     }
130 
131     /// Write ASN.1 DER-encoded PKCS#8 private key to the given path
132     #[cfg(feature = "std")]
133     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
write_pkcs8_der_file(&self, path: impl AsRef<Path>) -> Result<()>134     fn write_pkcs8_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
135         Ok(self.to_pkcs8_der()?.write_der_file(path)?)
136     }
137 
138     /// Write ASN.1 DER-encoded PKCS#8 private key to the given path
139     #[cfg(all(feature = "pem", feature = "std"))]
140     #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))]
write_pkcs8_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()>141     fn write_pkcs8_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> {
142         let doc = self.to_pkcs8_der()?;
143         Ok(doc.write_pem_file(path, PrivateKeyInfo::PEM_LABEL, line_ending)?)
144     }
145 }
146