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 pub trait DecodeEcPrivateKey: Sized { 25 /// Deserialize SEC1 private key from ASN.1 DER-encoded data 26 /// (binary format). from_sec1_der(bytes: &[u8]) -> Result<Self>27 fn from_sec1_der(bytes: &[u8]) -> Result<Self>; 28 29 /// Deserialize SEC1-encoded private key from PEM. 30 /// 31 /// Keys in this format begin with the following: 32 /// 33 /// ```text 34 /// -----BEGIN EC PRIVATE KEY----- 35 /// ``` 36 #[cfg(feature = "pem")] from_sec1_pem(s: &str) -> Result<Self>37 fn from_sec1_pem(s: &str) -> Result<Self> { 38 let (label, doc) = SecretDocument::from_pem(s)?; 39 EcPrivateKey::validate_pem_label(label)?; 40 Self::from_sec1_der(doc.as_bytes()) 41 } 42 43 /// Load SEC1 private key from an ASN.1 DER-encoded file on the local 44 /// filesystem (binary format). 45 #[cfg(feature = "std")] read_sec1_der_file(path: impl AsRef<Path>) -> Result<Self>46 fn read_sec1_der_file(path: impl AsRef<Path>) -> Result<Self> { 47 Self::from_sec1_der(SecretDocument::read_der_file(path)?.as_bytes()) 48 } 49 50 /// Load SEC1 private key from a PEM-encoded file on the local filesystem. 51 #[cfg(all(feature = "pem", feature = "std"))] read_sec1_pem_file(path: impl AsRef<Path>) -> Result<Self>52 fn read_sec1_pem_file(path: impl AsRef<Path>) -> Result<Self> { 53 let (label, doc) = SecretDocument::read_pem_file(path)?; 54 EcPrivateKey::validate_pem_label(&label)?; 55 Self::from_sec1_der(doc.as_bytes()) 56 } 57 } 58 59 /// Serialize a [`EcPrivateKey`] to a SEC1 encoded document. 60 #[cfg(feature = "alloc")] 61 pub trait EncodeEcPrivateKey { 62 /// Serialize a [`SecretDocument`] containing a SEC1-encoded private key. to_sec1_der(&self) -> Result<SecretDocument>63 fn to_sec1_der(&self) -> Result<SecretDocument>; 64 65 /// Serialize this private key as PEM-encoded SEC1 with the given [`LineEnding`]. 66 /// 67 /// To use the OS's native line endings, pass `Default::default()`. 68 #[cfg(feature = "pem")] to_sec1_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>>69 fn to_sec1_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>> { 70 let doc = self.to_sec1_der()?; 71 Ok(doc.to_pem(EcPrivateKey::PEM_LABEL, line_ending)?) 72 } 73 74 /// Write ASN.1 DER-encoded SEC1 private key to the given path. 75 #[cfg(feature = "std")] write_sec1_der_file(&self, path: impl AsRef<Path>) -> Result<()>76 fn write_sec1_der_file(&self, path: impl AsRef<Path>) -> Result<()> { 77 Ok(self.to_sec1_der()?.write_der_file(path)?) 78 } 79 80 /// Write ASN.1 DER-encoded SEC1 private key to the given path. 81 #[cfg(all(feature = "pem", feature = "std"))] write_sec1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()>82 fn write_sec1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> { 83 let doc = self.to_sec1_der()?; 84 Ok(doc.write_pem_file(path, EcPrivateKey::PEM_LABEL, line_ending)?) 85 } 86 } 87 88 #[cfg(feature = "pkcs8")] 89 impl<T> DecodeEcPrivateKey for T 90 where 91 T: for<'a> TryFrom<pkcs8::PrivateKeyInfo<'a>, Error = pkcs8::Error>, 92 { from_sec1_der(private_key: &[u8]) -> Result<Self>93 fn from_sec1_der(private_key: &[u8]) -> Result<Self> { 94 let params_oid = EcPrivateKey::from_der(private_key)? 95 .parameters 96 .and_then(|params| params.named_curve()); 97 98 let algorithm = pkcs8::AlgorithmIdentifierRef { 99 oid: ALGORITHM_OID, 100 parameters: params_oid.as_ref().map(Into::into), 101 }; 102 103 Ok(Self::try_from(pkcs8::PrivateKeyInfo { 104 algorithm, 105 private_key, 106 public_key: None, 107 })?) 108 } 109 } 110 111 #[cfg(all(feature = "alloc", feature = "pkcs8"))] 112 impl<T: pkcs8::EncodePrivateKey> EncodeEcPrivateKey for T { to_sec1_der(&self) -> Result<SecretDocument>113 fn to_sec1_der(&self) -> Result<SecretDocument> { 114 let doc = self.to_pkcs8_der()?; 115 let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(doc.as_bytes())?; 116 pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; 117 118 let mut pkcs1_key = EcPrivateKey::from_der(pkcs8_key.private_key)?; 119 pkcs1_key.parameters = Some(pkcs8_key.algorithm.parameters_oid()?.into()); 120 pkcs1_key.try_into() 121 } 122 } 123