1 //! Traits for parsing objects from PKCS#8 encoded documents
3 use crate::{Error, PrivateKeyInfo, Result}
;
5 #[cfg(feature = "alloc")]
6 use der
::SecretDocument
;
8 #[cfg(feature = "encryption")]
10 crate::EncryptedPrivateKeyInfo
,
11 rand_core
::{CryptoRng, RngCore}
,
14 #[cfg(feature = "pem")]
15 use {crate::LineEnding, alloc::string::String, der::zeroize::Zeroizing}
;
17 #[cfg(feature = "pem")]
18 use der
::pem
::PemLabel
;
20 #[cfg(feature = "std")]
23 /// Parse a private key object from a PKCS#8 encoded document.
24 pub trait DecodePrivateKey
: Sized
{
25 /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data
27 fn from_pkcs8_der(bytes
: &[u8]) -> Result
<Self>;
29 /// Deserialize encrypted PKCS#8 private key from ASN.1 DER-encoded data
30 /// (binary format) and attempt to decrypt it using the provided password.
31 #[cfg(feature = "encryption")]
32 fn from_pkcs8_encrypted_der(bytes
: &[u8], password
: impl AsRef
<[u8]>) -> Result
<Self> {
33 let doc
= EncryptedPrivateKeyInfo
::try_from(bytes
)?
.decrypt(password
)?
;
34 Self::from_pkcs8_der(doc
.as_bytes())
37 /// Deserialize PKCS#8-encoded private key from PEM.
39 /// Keys in this format begin with the following delimiter:
42 /// -----BEGIN PRIVATE KEY-----
44 #[cfg(feature = "pem")]
45 fn from_pkcs8_pem(s
: &str) -> Result
<Self> {
46 let (label
, doc
) = SecretDocument
::from_pem(s
)?
;
47 PrivateKeyInfo
::validate_pem_label(label
)?
;
48 Self::from_pkcs8_der(doc
.as_bytes())
51 /// Deserialize encrypted PKCS#8-encoded private key from PEM and attempt
52 /// to decrypt it using the provided password.
54 /// Keys in this format begin with the following delimiter:
57 /// -----BEGIN ENCRYPTED PRIVATE KEY-----
59 #[cfg(all(feature = "encryption", feature = "pem"))]
60 fn from_pkcs8_encrypted_pem(s
: &str, password
: impl AsRef
<[u8]>) -> Result
<Self> {
61 let (label
, doc
) = SecretDocument
::from_pem(s
)?
;
62 EncryptedPrivateKeyInfo
::validate_pem_label(label
)?
;
63 Self::from_pkcs8_encrypted_der(doc
.as_bytes(), password
)
66 /// Load PKCS#8 private key from an ASN.1 DER-encoded file on the local
67 /// filesystem (binary format).
68 #[cfg(feature = "std")]
69 fn read_pkcs8_der_file(path
: impl AsRef
<Path
>) -> Result
<Self> {
70 Self::from_pkcs8_der(SecretDocument
::read_der_file(path
)?
.as_bytes())
73 /// Load PKCS#8 private key from a PEM-encoded file on the local filesystem.
74 #[cfg(all(feature = "pem", feature = "std"))]
75 fn read_pkcs8_pem_file(path
: impl AsRef
<Path
>) -> Result
<Self> {
76 let (label
, doc
) = SecretDocument
::read_pem_file(path
)?
;
77 PrivateKeyInfo
::validate_pem_label(&label
)?
;
78 Self::from_pkcs8_der(doc
.as_bytes())
82 impl<T
> DecodePrivateKey
for T
84 T
: for<'a
> TryFrom
<PrivateKeyInfo
<'a
>, Error
= Error
>,
86 fn from_pkcs8_der(bytes
: &[u8]) -> Result
<Self> {
87 Self::try_from(PrivateKeyInfo
::try_from(bytes
)?
)
91 /// Serialize a private key object to a PKCS#8 encoded document.
92 #[cfg(feature = "alloc")]
93 pub trait EncodePrivateKey
{
94 /// Serialize a [`SecretDocument`] containing a PKCS#8-encoded private key.
95 fn to_pkcs8_der(&self) -> Result
<SecretDocument
>;
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 fn to_pkcs8_encrypted_der(
102 rng
: impl CryptoRng
+ RngCore
,
103 password
: impl AsRef
<[u8]>,
104 ) -> Result
<SecretDocument
> {
105 EncryptedPrivateKeyInfo
::encrypt(rng
, password
, self.to_pkcs8_der()?
.as_bytes())
108 /// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`].
109 #[cfg(feature = "pem")]
110 fn to_pkcs8_pem(&self, line_ending
: LineEnding
) -> Result
<Zeroizing
<String
>> {
111 let doc
= self.to_pkcs8_der()?
;
112 Ok(doc
.to_pem(PrivateKeyInfo
::PEM_LABEL
, line_ending
)?
)
115 /// Serialize this private key as an encrypted PEM-encoded PKCS#8 private
116 /// key using the `provided` to derive an encryption key.
117 #[cfg(all(feature = "encryption", feature = "pem"))]
118 fn to_pkcs8_encrypted_pem(
120 rng
: impl CryptoRng
+ RngCore
,
121 password
: impl AsRef
<[u8]>,
122 line_ending
: LineEnding
,
123 ) -> Result
<Zeroizing
<String
>> {
124 let doc
= self.to_pkcs8_encrypted_der(rng
, password
)?
;
125 Ok(doc
.to_pem(EncryptedPrivateKeyInfo
::PEM_LABEL
, line_ending
)?
)
128 /// Write ASN.1 DER-encoded PKCS#8 private key to the given path
129 #[cfg(feature = "std")]
130 fn write_pkcs8_der_file(&self, path
: impl AsRef
<Path
>) -> Result
<()> {
131 Ok(self.to_pkcs8_der()?
.write_der_file(path
)?
)
134 /// Write ASN.1 DER-encoded PKCS#8 private key to the given path
135 #[cfg(all(feature = "pem", feature = "std"))]
136 fn write_pkcs8_pem_file(&self, path
: impl AsRef
<Path
>, line_ending
: LineEnding
) -> Result
<()> {
137 let doc
= self.to_pkcs8_der()?
;
138 Ok(doc
.write_pem_file(path
, PrivateKeyInfo
::PEM_LABEL
, line_ending
)?
)