• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Traits for parsing objects from SEC1 encoded documents
2 
3 use crate::Result;
4 
5 #[cfg(feature = "alloc")]
6 use der::SecretDocument;
7 
8 #[cfg(feature = "pem")]
9 use {crate::LineEnding, alloc::string::String, der::pem::PemLabel};
10 
11 #[cfg(feature = "pkcs8")]
12 use {
13     crate::{EcPrivateKey, ALGORITHM_OID},
14     der::Decode,
15 };
16 
17 #[cfg(feature = "std")]
18 use std::path::Path;
19 
20 #[cfg(feature = "pem")]
21 use zeroize::Zeroizing;
22 
23 /// Parse an [`EcPrivateKey`] from a SEC1-encoded document.
24 #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
25 pub trait DecodeEcPrivateKey: Sized {
26     /// Deserialize SEC1 private key from ASN.1 DER-encoded data
27     /// (binary format).
from_sec1_der(bytes: &[u8]) -> Result<Self>28     fn from_sec1_der(bytes: &[u8]) -> Result<Self>;
29 
30     /// Deserialize SEC1-encoded private key from PEM.
31     ///
32     /// Keys in this format begin with the following:
33     ///
34     /// ```text
35     /// -----BEGIN EC PRIVATE KEY-----
36     /// ```
37     #[cfg(feature = "pem")]
38     #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
from_sec1_pem(s: &str) -> Result<Self>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     /// Load SEC1 private key from an ASN.1 DER-encoded file on the local
46     /// filesystem (binary format).
47     #[cfg(feature = "std")]
48     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read_sec1_der_file(path: impl AsRef<Path>) -> Result<Self>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     /// Load SEC1 private key from a PEM-encoded file on the local filesystem.
54     #[cfg(all(feature = "pem", feature = "std"))]
55     #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
56     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read_sec1_pem_file(path: impl AsRef<Path>) -> Result<Self>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 /// Serialize a [`EcPrivateKey`] to a SEC1 encoded document.
65 #[cfg(feature = "alloc")]
66 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "der"))))]
67 pub trait EncodeEcPrivateKey {
68     /// Serialize a [`SecretDocument`] containing a SEC1-encoded private key.
to_sec1_der(&self) -> Result<SecretDocument>69     fn to_sec1_der(&self) -> Result<SecretDocument>;
70 
71     /// Serialize this private key as PEM-encoded SEC1 with the given [`LineEnding`].
72     ///
73     /// To use the OS's native line endings, pass `Default::default()`.
74     #[cfg(feature = "pem")]
75     #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
to_sec1_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>>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     /// Write ASN.1 DER-encoded SEC1 private key to the given path.
82     #[cfg(feature = "std")]
83     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
write_sec1_der_file(&self, path: impl AsRef<Path>) -> Result<()>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     /// Write ASN.1 DER-encoded SEC1 private key to the given path.
89     #[cfg(all(feature = "pem", feature = "std"))]
90     #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
91     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
write_sec1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()>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")))]
100 impl<T: pkcs8::DecodePrivateKey> DecodeEcPrivateKey for T {
from_sec1_der(private_key: &[u8]) -> Result<Self>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"))))]
121 impl<T: pkcs8::EncodePrivateKey> EncodeEcPrivateKey for T {
to_sec1_der(&self) -> Result<SecretDocument>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 }
132