1use crate::{Error, PrivateKeyInfo, Result};
4
5#[cfg(feature = "alloc")]
6use der::SecretDocument;
7
8#[cfg(feature = "encryption")]
9use {
10    crate::EncryptedPrivateKeyInfo,
11    rand_core::{CryptoRng, RngCore},
12};
13
14#[cfg(feature = "pem")]
15use {crate::LineEnding, alloc::string::String, der::zeroize::Zeroizing};
16
17#[cfg(feature = "pem")]
18use der::pem::PemLabel;
19
20#[cfg(feature = "std")]
21use std::path::Path;
22
23pub trait DecodePrivateKey: Sized {
25    fn from_pkcs8_der(bytes: &[u8]) -> Result<Self>;
28
29    #[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())
35    }
36
37    #[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())
49    }
50
51    #[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)
64    }
65
66    #[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())
71    }
72
73    #[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())
79    }
80}
81
82impl<T> DecodePrivateKey for T
83where
84    T: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error>,
85{
86    fn from_pkcs8_der(bytes: &[u8]) -> Result<Self> {
87        Self::try_from(PrivateKeyInfo::try_from(bytes)?)
88    }
89}
90
91#[cfg(feature = "alloc")]
93pub trait EncodePrivateKey {
94    fn to_pkcs8_der(&self) -> Result<SecretDocument>;
96
97    #[cfg(feature = "encryption")]
100    fn to_pkcs8_encrypted_der(
101        &self,
102        rng: impl CryptoRng + RngCore,
103        password: impl AsRef<[u8]>,
104    ) -> Result<SecretDocument> {
105        EncryptedPrivateKeyInfo::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes())
106    }
107
108    #[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)?)
113    }
114
115    #[cfg(all(feature = "encryption", feature = "pem"))]
118    fn to_pkcs8_encrypted_pem(
119        &self,
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)?)
126    }
127
128    #[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)?)
132    }
133
134    #[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)?)
139    }
140}