1use crate::Result;
4
5#[cfg(feature = "alloc")]
6use crate::EcPrivateKeyDocument;
7
8#[cfg(feature = "pem")]
9use {crate::LineEnding, alloc::string::String};
10
11#[cfg(feature = "pkcs8")]
12use {
13 crate::{EcPrivateKey, ALGORITHM_OID},
14 der::Decodable,
15};
16
17#[cfg(all(feature = "alloc", feature = "pkcs8"))]
18use der::Document;
19
20#[cfg(feature = "std")]
21use std::path::Path;
22
23#[cfg(any(feature = "pem", feature = "std"))]
24use zeroize::Zeroizing;
25
26pub trait DecodeEcPrivateKey: Sized {
28 fn from_sec1_der(bytes: &[u8]) -> Result<Self>;
31
32 #[cfg(feature = "pem")]
40 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
41 fn from_sec1_pem(s: &str) -> Result<Self> {
42 EcPrivateKeyDocument::from_sec1_pem(s).and_then(|doc| Self::from_sec1_der(doc.as_der()))
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 EcPrivateKeyDocument::read_sec1_der_file(path)
51 .and_then(|doc| Self::from_sec1_der(doc.as_der()))
52 }
53
54 #[cfg(all(feature = "pem", feature = "std"))]
56 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
57 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
58 fn read_sec1_pem_file(path: impl AsRef<Path>) -> Result<Self> {
59 EcPrivateKeyDocument::read_sec1_pem_file(path)
60 .and_then(|doc| Self::from_sec1_der(doc.as_der()))
61 }
62}
63
64#[cfg(feature = "alloc")]
66#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
67pub trait EncodeEcPrivateKey {
68 fn to_sec1_der(&self) -> Result<EcPrivateKeyDocument>;
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 self.to_sec1_der()?.to_sec1_pem(line_ending)
78 }
79
80 #[cfg(feature = "std")]
82 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
83 fn write_sec1_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
84 self.to_sec1_der()?.write_sec1_der_file(path)
85 }
86
87 #[cfg(all(feature = "pem", feature = "std"))]
89 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
90 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
91 fn write_sec1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> {
92 self.to_sec1_der()?.write_sec1_pem_file(path, line_ending)
93 }
94}
95
96#[cfg(feature = "pkcs8")]
97#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
98impl<T: pkcs8::DecodePrivateKey> DecodeEcPrivateKey for T {
99 fn from_sec1_der(private_key: &[u8]) -> Result<Self> {
100 let params_oid = EcPrivateKey::from_der(private_key)?
101 .parameters
102 .and_then(|params| params.named_curve());
103
104 let algorithm = pkcs8::AlgorithmIdentifier {
105 oid: ALGORITHM_OID,
106 parameters: params_oid.as_ref().map(Into::into),
107 };
108
109 Ok(Self::try_from(pkcs8::PrivateKeyInfo {
110 algorithm,
111 private_key,
112 public_key: None,
113 })?)
114 }
115}
116
117#[cfg(all(feature = "alloc", feature = "pkcs8"))]
118#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs8"))))]
119impl<T: pkcs8::EncodePrivateKey> EncodeEcPrivateKey for T {
120 fn to_sec1_der(&self) -> Result<EcPrivateKeyDocument> {
121 let doc = self.to_pkcs8_der()?;
122 let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(doc.as_der())?;
123 let mut pkcs1_key = EcPrivateKey::from_der(pkcs8_key.private_key)?;
124 pkcs1_key.parameters = Some(pkcs8_key.algorithm.parameters_oid()?.into());
125 pkcs1_key.try_into()
126 }
127}