1use crate::Result;
4
5#[cfg(feature = "alloc")]
6use der::SecretDocument;
7
8#[cfg(feature = "pem")]
9use {crate::LineEnding, alloc::string::String, der::pem::PemLabel};
10
11#[cfg(feature = "pkcs8")]
12use {
13 crate::{EcPrivateKey, ALGORITHM_OID},
14 der::Decode,
15};
16
17#[cfg(feature = "std")]
18use std::path::Path;
19
20#[cfg(feature = "pem")]
21use zeroize::Zeroizing;
22
23#[cfg_attr(docsrs, doc(cfg(feature = "der")))]
25pub trait DecodeEcPrivateKey: Sized {
26 fn from_sec1_der(bytes: &[u8]) -> Result<Self>;
29
30 #[cfg(feature = "pem")]
38 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
39 fn from_sec1_pem(s: &str) -> Result<Self> {
40 let (label, doc) = SecretDocument::from_pem(s)?;
41 EcPrivateKey::validate_pem_label(label)?;
42 Self::from_sec1_der(doc.as_bytes())
43 }
44
45 #[cfg(feature = "std")]
48 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
49 fn read_sec1_der_file(path: impl AsRef<Path>) -> Result<Self> {
50 Self::from_sec1_der(SecretDocument::read_der_file(path)?.as_bytes())
51 }
52
53 #[cfg(all(feature = "pem", feature = "std"))]
55 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
56 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
57 fn read_sec1_pem_file(path: impl AsRef<Path>) -> Result<Self> {
58 let (label, doc) = SecretDocument::read_pem_file(path)?;
59 EcPrivateKey::validate_pem_label(&label)?;
60 Self::from_sec1_der(doc.as_bytes())
61 }
62}
63
64#[cfg(feature = "alloc")]
66#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "der"))))]
67pub trait EncodeEcPrivateKey {
68 fn to_sec1_der(&self) -> Result<SecretDocument>;
70
71 #[cfg(feature = "pem")]
75 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
76 fn to_sec1_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>> {
77 let doc = self.to_sec1_der()?;
78 Ok(doc.to_pem(EcPrivateKey::PEM_LABEL, line_ending)?)
79 }
80
81 #[cfg(feature = "std")]
83 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
84 fn write_sec1_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
85 Ok(self.to_sec1_der()?.write_der_file(path)?)
86 }
87
88 #[cfg(all(feature = "pem", feature = "std"))]
90 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
91 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
92 fn write_sec1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> {
93 let doc = self.to_sec1_der()?;
94 Ok(doc.write_pem_file(path, EcPrivateKey::PEM_LABEL, line_ending)?)
95 }
96}
97
98#[cfg(feature = "pkcs8")]
99#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
100impl<T: pkcs8::DecodePrivateKey> DecodeEcPrivateKey for T {
101 fn from_sec1_der(private_key: &[u8]) -> Result<Self> {
102 let params_oid = EcPrivateKey::from_der(private_key)?
103 .parameters
104 .and_then(|params| params.named_curve());
105
106 let algorithm = pkcs8::AlgorithmIdentifier {
107 oid: ALGORITHM_OID,
108 parameters: params_oid.as_ref().map(Into::into),
109 };
110
111 Ok(Self::try_from(pkcs8::PrivateKeyInfo {
112 algorithm,
113 private_key,
114 public_key: None,
115 })?)
116 }
117}
118
119#[cfg(all(feature = "alloc", feature = "pkcs8"))]
120#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs8"))))]
121impl<T: pkcs8::EncodePrivateKey> EncodeEcPrivateKey for T {
122 fn to_sec1_der(&self) -> Result<SecretDocument> {
123 let doc = self.to_pkcs8_der()?;
124 let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(doc.as_bytes())?;
125 pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?;
126
127 let mut pkcs1_key = EcPrivateKey::from_der(pkcs8_key.private_key)?;
128 pkcs1_key.parameters = Some(pkcs8_key.algorithm.parameters_oid()?.into());
129 pkcs1_key.try_into()
130 }
131}