1 //! Traits for encoding/decoding SPKI public keys. 2 3 use crate::{Error, Result, SubjectPublicKeyInfo}; 4 5 #[cfg(feature = "alloc")] 6 use der::Document; 7 8 #[cfg(feature = "pem")] 9 use { 10 alloc::string::String, 11 der::pem::{LineEnding, PemLabel}, 12 }; 13 14 #[cfg(feature = "std")] 15 use std::path::Path; 16 17 /// Parse a public key object from an encoded SPKI document. 18 pub trait DecodePublicKey: 19 for<'a> TryFrom<SubjectPublicKeyInfo<'a>, Error = Error> + Sized 20 { 21 /// Deserialize object from ASN.1 DER-encoded [`SubjectPublicKeyInfo`] 22 /// (binary format). from_public_key_der(bytes: &[u8]) -> Result<Self>23 fn from_public_key_der(bytes: &[u8]) -> Result<Self> { 24 Self::try_from(SubjectPublicKeyInfo::try_from(bytes)?) 25 } 26 27 /// Deserialize PEM-encoded [`SubjectPublicKeyInfo`]. 28 /// 29 /// Keys in this format begin with the following delimiter: 30 /// 31 /// ```text 32 /// -----BEGIN PUBLIC KEY----- 33 /// ``` 34 #[cfg(feature = "pem")] 35 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] from_public_key_pem(s: &str) -> Result<Self>36 fn from_public_key_pem(s: &str) -> Result<Self> { 37 let (label, doc) = Document::from_pem(s)?; 38 SubjectPublicKeyInfo::validate_pem_label(label)?; 39 Self::from_public_key_der(doc.as_bytes()) 40 } 41 42 /// Load public key object from an ASN.1 DER-encoded file on the local 43 /// filesystem (binary format). 44 #[cfg(feature = "std")] 45 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read_public_key_der_file(path: impl AsRef<Path>) -> Result<Self>46 fn read_public_key_der_file(path: impl AsRef<Path>) -> Result<Self> { 47 let doc = Document::read_der_file(path)?; 48 Self::from_public_key_der(doc.as_bytes()) 49 } 50 51 /// Load public key object from a PEM-encoded file on the local filesystem. 52 #[cfg(all(feature = "pem", feature = "std"))] 53 #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))] read_public_key_pem_file(path: impl AsRef<Path>) -> Result<Self>54 fn read_public_key_pem_file(path: impl AsRef<Path>) -> Result<Self> { 55 let (label, doc) = Document::read_pem_file(path)?; 56 SubjectPublicKeyInfo::validate_pem_label(&label)?; 57 Self::from_public_key_der(doc.as_bytes()) 58 } 59 } 60 61 /// Serialize a public key object to a SPKI-encoded document. 62 #[cfg(feature = "alloc")] 63 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 64 pub trait EncodePublicKey { 65 /// Serialize a [`Document`] containing a SPKI-encoded public key. to_public_key_der(&self) -> Result<Document>66 fn to_public_key_der(&self) -> Result<Document>; 67 68 /// Serialize this public key as PEM-encoded SPKI with the given [`LineEnding`]. 69 #[cfg(feature = "pem")] 70 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] to_public_key_pem(&self, line_ending: LineEnding) -> Result<String>71 fn to_public_key_pem(&self, line_ending: LineEnding) -> Result<String> { 72 let doc = self.to_public_key_der()?; 73 Ok(doc.to_pem(SubjectPublicKeyInfo::PEM_LABEL, line_ending)?) 74 } 75 76 /// Write ASN.1 DER-encoded public key to the given path 77 #[cfg(feature = "std")] 78 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] write_public_key_der_file(&self, path: impl AsRef<Path>) -> Result<()>79 fn write_public_key_der_file(&self, path: impl AsRef<Path>) -> Result<()> { 80 Ok(self.to_public_key_der()?.write_der_file(path)?) 81 } 82 83 /// Write ASN.1 DER-encoded public key to the given path 84 #[cfg(all(feature = "pem", feature = "std"))] 85 #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))] write_public_key_pem_file( &self, path: impl AsRef<Path>, line_ending: LineEnding, ) -> Result<()>86 fn write_public_key_pem_file( 87 &self, 88 path: impl AsRef<Path>, 89 line_ending: LineEnding, 90 ) -> Result<()> { 91 let doc = self.to_public_key_der()?; 92 Ok(doc.write_pem_file(path, SubjectPublicKeyInfo::PEM_LABEL, line_ending)?) 93 } 94 } 95