1 //! Traits for encoding/decoding SPKI public keys. 2 3 use crate::{AlgorithmIdentifier, Error, Result, SubjectPublicKeyInfoRef}; 4 use der::{EncodeValue, Tagged}; 5 6 #[cfg(feature = "alloc")] 7 use { 8 crate::AlgorithmIdentifierOwned, 9 der::{asn1::BitString, Any, Document}, 10 }; 11 12 #[cfg(feature = "pem")] 13 use { 14 alloc::string::String, 15 der::pem::{LineEnding, PemLabel}, 16 }; 17 18 #[cfg(feature = "std")] 19 use std::path::Path; 20 21 #[cfg(doc)] 22 use crate::SubjectPublicKeyInfo; 23 24 /// Parse a public key object from an encoded SPKI document. 25 pub trait DecodePublicKey: Sized { 26 /// Deserialize object from ASN.1 DER-encoded [`SubjectPublicKeyInfo`] 27 /// (binary format). from_public_key_der(bytes: &[u8]) -> Result<Self>28 fn from_public_key_der(bytes: &[u8]) -> Result<Self>; 29 30 /// Deserialize PEM-encoded [`SubjectPublicKeyInfo`]. 31 /// 32 /// Keys in this format begin with the following delimiter: 33 /// 34 /// ```text 35 /// -----BEGIN PUBLIC KEY----- 36 /// ``` 37 #[cfg(feature = "pem")] from_public_key_pem(s: &str) -> Result<Self>38 fn from_public_key_pem(s: &str) -> Result<Self> { 39 let (label, doc) = Document::from_pem(s)?; 40 SubjectPublicKeyInfoRef::validate_pem_label(label)?; 41 Self::from_public_key_der(doc.as_bytes()) 42 } 43 44 /// Load public key object from an ASN.1 DER-encoded file on the local 45 /// filesystem (binary format). 46 #[cfg(feature = "std")] read_public_key_der_file(path: impl AsRef<Path>) -> Result<Self>47 fn read_public_key_der_file(path: impl AsRef<Path>) -> Result<Self> { 48 let doc = Document::read_der_file(path)?; 49 Self::from_public_key_der(doc.as_bytes()) 50 } 51 52 /// Load public key object from a PEM-encoded file on the local filesystem. 53 #[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 SubjectPublicKeyInfoRef::validate_pem_label(&label)?; 57 Self::from_public_key_der(doc.as_bytes()) 58 } 59 } 60 61 impl<T> DecodePublicKey for T 62 where 63 T: for<'a> TryFrom<SubjectPublicKeyInfoRef<'a>, Error = Error>, 64 { from_public_key_der(bytes: &[u8]) -> Result<Self>65 fn from_public_key_der(bytes: &[u8]) -> Result<Self> { 66 Self::try_from(SubjectPublicKeyInfoRef::try_from(bytes)?) 67 } 68 } 69 70 /// Serialize a public key object to a SPKI-encoded document. 71 #[cfg(feature = "alloc")] 72 pub trait EncodePublicKey { 73 /// Serialize a [`Document`] containing a SPKI-encoded public key. to_public_key_der(&self) -> Result<Document>74 fn to_public_key_der(&self) -> Result<Document>; 75 76 /// Serialize this public key as PEM-encoded SPKI with the given [`LineEnding`]. 77 #[cfg(feature = "pem")] to_public_key_pem(&self, line_ending: LineEnding) -> Result<String>78 fn to_public_key_pem(&self, line_ending: LineEnding) -> Result<String> { 79 let doc = self.to_public_key_der()?; 80 Ok(doc.to_pem(SubjectPublicKeyInfoRef::PEM_LABEL, line_ending)?) 81 } 82 83 /// Write ASN.1 DER-encoded public key to the given path 84 #[cfg(feature = "std")] write_public_key_der_file(&self, path: impl AsRef<Path>) -> Result<()>85 fn write_public_key_der_file(&self, path: impl AsRef<Path>) -> Result<()> { 86 Ok(self.to_public_key_der()?.write_der_file(path)?) 87 } 88 89 /// Write ASN.1 DER-encoded public key to the given path 90 #[cfg(all(feature = "pem", feature = "std"))] write_public_key_pem_file( &self, path: impl AsRef<Path>, line_ending: LineEnding, ) -> Result<()>91 fn write_public_key_pem_file( 92 &self, 93 path: impl AsRef<Path>, 94 line_ending: LineEnding, 95 ) -> Result<()> { 96 let doc = self.to_public_key_der()?; 97 Ok(doc.write_pem_file(path, SubjectPublicKeyInfoRef::PEM_LABEL, line_ending)?) 98 } 99 } 100 101 /// Returns `AlgorithmIdentifier` associated with the structure. 102 /// 103 /// This is useful for e.g. keys for digital signature algorithms. 104 pub trait AssociatedAlgorithmIdentifier { 105 /// Algorithm parameters. 106 type Params: Tagged + EncodeValue; 107 108 /// `AlgorithmIdentifier` for this structure. 109 const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params>; 110 } 111 112 /// Returns `AlgorithmIdentifier` associated with the structure. 113 /// 114 /// This is useful for e.g. keys for digital signature algorithms. 115 #[cfg(feature = "alloc")] 116 pub trait DynAssociatedAlgorithmIdentifier { 117 /// `AlgorithmIdentifier` for this structure. algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>118 fn algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>; 119 } 120 121 #[cfg(feature = "alloc")] 122 impl<T> DynAssociatedAlgorithmIdentifier for T 123 where 124 T: AssociatedAlgorithmIdentifier, 125 { algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>126 fn algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned> { 127 Ok(AlgorithmIdentifierOwned { 128 oid: T::ALGORITHM_IDENTIFIER.oid, 129 parameters: T::ALGORITHM_IDENTIFIER 130 .parameters 131 .as_ref() 132 .map(Any::encode_from) 133 .transpose()?, 134 }) 135 } 136 } 137 138 /// Returns `AlgorithmIdentifier` associated with the signature system. 139 /// 140 /// Unlike AssociatedAlgorithmIdentifier this is intended to be implemented for public and/or 141 /// private keys. 142 pub trait SignatureAlgorithmIdentifier { 143 /// Algorithm parameters. 144 type Params: Tagged + EncodeValue; 145 146 /// `AlgorithmIdentifier` for the corresponding singature system. 147 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params>; 148 } 149 150 /// Returns `AlgorithmIdentifier` associated with the signature system. 151 /// 152 /// Unlike AssociatedAlgorithmIdentifier this is intended to be implemented for public and/or 153 /// private keys. 154 #[cfg(feature = "alloc")] 155 pub trait DynSignatureAlgorithmIdentifier { 156 /// `AlgorithmIdentifier` for the corresponding singature system. signature_algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>157 fn signature_algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>; 158 } 159 160 #[cfg(feature = "alloc")] 161 impl<T> DynSignatureAlgorithmIdentifier for T 162 where 163 T: SignatureAlgorithmIdentifier, 164 { signature_algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>165 fn signature_algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned> { 166 Ok(AlgorithmIdentifierOwned { 167 oid: T::SIGNATURE_ALGORITHM_IDENTIFIER.oid, 168 parameters: T::SIGNATURE_ALGORITHM_IDENTIFIER 169 .parameters 170 .as_ref() 171 .map(Any::encode_from) 172 .transpose()?, 173 }) 174 } 175 } 176 177 /// Returns the `BitString` encoding of the signature. 178 /// 179 /// X.509 and CSR structures require signatures to be BitString encoded. 180 #[cfg(feature = "alloc")] 181 pub trait SignatureBitStringEncoding { 182 /// `BitString` encoding for this signature. to_bitstring(&self) -> der::Result<BitString>183 fn to_bitstring(&self) -> der::Result<BitString>; 184 } 185