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: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error> + Sized {
25 fn from_pkcs8_der(bytes: &[u8]) -> Result<Self> {
28 Self::try_from(PrivateKeyInfo::try_from(bytes)?)
29 }
30
31 #[cfg(feature = "encryption")]
34 #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
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 #[cfg(feature = "pem")]
48 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
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 #[cfg(all(feature = "encryption", feature = "pem"))]
64 #[cfg_attr(docsrs, doc(cfg(all(feature = "encryption", feature = "pem"))))]
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 #[cfg(feature = "std")]
74 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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 #[cfg(all(feature = "pem", feature = "std"))]
81 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
82 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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#[cfg(feature = "alloc")]
92#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
93pub trait EncodePrivateKey {
94 fn to_pkcs8_der(&self) -> Result<SecretDocument>;
96
97 #[cfg(feature = "encryption")]
100 #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
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 #[cfg(feature = "pem")]
111 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
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 #[cfg(all(feature = "encryption", feature = "pem"))]
120 #[cfg_attr(docsrs, doc(cfg(all(feature = "encryption", feature = "pem"))))]
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 #[cfg(feature = "std")]
133 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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 #[cfg(all(feature = "pem", feature = "std"))]
140 #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))]
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}