1 //! X.509 `SubjectPublicKeyInfo` 2 3 use crate::{AlgorithmIdentifier, Error, Result}; 4 use core::cmp::Ordering; 5 use der::{ 6 asn1::{AnyRef, BitStringRef}, 7 Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, Header, Length, Reader, 8 Sequence, ValueOrd, Writer, 9 }; 10 11 #[cfg(feature = "alloc")] 12 use der::{ 13 asn1::{Any, BitString}, 14 Document, 15 }; 16 17 #[cfg(feature = "fingerprint")] 18 use crate::{fingerprint, FingerprintBytes}; 19 20 #[cfg(feature = "pem")] 21 use der::pem::PemLabel; 22 23 /// [`SubjectPublicKeyInfo`] with [`AnyRef`] algorithm parameters, and [`BitStringRef`] params. 24 pub type SubjectPublicKeyInfoRef<'a> = SubjectPublicKeyInfo<AnyRef<'a>, BitStringRef<'a>>; 25 26 /// [`SubjectPublicKeyInfo`] with [`Any`] algorithm parameters, and [`BitString`] params. 27 #[cfg(feature = "alloc")] 28 pub type SubjectPublicKeyInfoOwned = SubjectPublicKeyInfo<Any, BitString>; 29 30 /// X.509 `SubjectPublicKeyInfo` (SPKI) as defined in [RFC 5280 § 4.1.2.7]. 31 /// 32 /// ASN.1 structure containing an [`AlgorithmIdentifier`] and public key 33 /// data in an algorithm specific format. 34 /// 35 /// ```text 36 /// SubjectPublicKeyInfo ::= SEQUENCE { 37 /// algorithm AlgorithmIdentifier, 38 /// subjectPublicKey BIT STRING } 39 /// ``` 40 /// 41 /// [RFC 5280 § 4.1.2.7]: https://tools.ietf.org/html/rfc5280#section-4.1.2.7 42 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 43 #[derive(Clone, Debug, Eq, PartialEq)] 44 pub struct SubjectPublicKeyInfo<Params, Key> { 45 /// X.509 [`AlgorithmIdentifier`] for the public key type 46 pub algorithm: AlgorithmIdentifier<Params>, 47 48 /// Public key data 49 pub subject_public_key: Key, 50 } 51 52 impl<'a, Params, Key> SubjectPublicKeyInfo<Params, Key> 53 where 54 Params: Choice<'a> + Encode, 55 // TODO: replace FixedTag with FixedTag<TAG = { Tag::BitString }> once 56 // https://github.com/rust-lang/rust/issues/92827 is fixed 57 Key: Decode<'a> + Encode + FixedTag, 58 { 59 /// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] and 60 /// encode it as a Base64 string. 61 /// 62 /// See [RFC7469 § 2.1.1] for more information. 63 /// 64 /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1 65 #[cfg(all(feature = "fingerprint", feature = "alloc", feature = "base64"))] fingerprint_base64(&self) -> Result<alloc::string::String>66 pub fn fingerprint_base64(&self) -> Result<alloc::string::String> { 67 use base64ct::{Base64, Encoding}; 68 Ok(Base64::encode_string(&self.fingerprint_bytes()?)) 69 } 70 71 /// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] as 72 /// a raw byte array. 73 /// 74 /// See [RFC7469 § 2.1.1] for more information. 75 /// 76 /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1 77 #[cfg(feature = "fingerprint")] fingerprint_bytes(&self) -> Result<FingerprintBytes>78 pub fn fingerprint_bytes(&self) -> Result<FingerprintBytes> { 79 let mut builder = fingerprint::Builder::new(); 80 self.encode(&mut builder)?; 81 Ok(builder.finish()) 82 } 83 } 84 85 impl<'a: 'k, 'k, Params, Key: 'k> DecodeValue<'a> for SubjectPublicKeyInfo<Params, Key> 86 where 87 Params: Choice<'a> + Encode, 88 Key: Decode<'a>, 89 { decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self>90 fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> { 91 reader.read_nested(header.length, |reader| { 92 Ok(Self { 93 algorithm: reader.decode()?, 94 subject_public_key: Key::decode(reader)?, 95 }) 96 }) 97 } 98 } 99 100 impl<'a, Params, Key> EncodeValue for SubjectPublicKeyInfo<Params, Key> 101 where 102 Params: Choice<'a> + Encode, 103 Key: Encode, 104 { value_len(&self) -> der::Result<Length>105 fn value_len(&self) -> der::Result<Length> { 106 self.algorithm.encoded_len()? + self.subject_public_key.encoded_len()? 107 } 108 encode_value(&self, writer: &mut impl Writer) -> der::Result<()>109 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { 110 self.algorithm.encode(writer)?; 111 self.subject_public_key.encode(writer)?; 112 Ok(()) 113 } 114 } 115 116 impl<'a, Params, Key> Sequence<'a> for SubjectPublicKeyInfo<Params, Key> 117 where 118 Params: Choice<'a> + Encode, 119 Key: Decode<'a> + Encode + FixedTag, 120 { 121 } 122 123 impl<'a, Params, Key> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<Params, Key> 124 where 125 Params: Choice<'a> + Encode, 126 Key: Decode<'a> + Encode + FixedTag, 127 { 128 type Error = Error; 129 try_from(bytes: &'a [u8]) -> Result<Self>130 fn try_from(bytes: &'a [u8]) -> Result<Self> { 131 Ok(Self::from_der(bytes)?) 132 } 133 } 134 135 impl<'a, Params, Key> ValueOrd for SubjectPublicKeyInfo<Params, Key> 136 where 137 Params: Choice<'a> + DerOrd + Encode, 138 Key: ValueOrd, 139 { value_cmp(&self, other: &Self) -> der::Result<Ordering>140 fn value_cmp(&self, other: &Self) -> der::Result<Ordering> { 141 match self.algorithm.der_cmp(&other.algorithm)? { 142 Ordering::Equal => self.subject_public_key.value_cmp(&other.subject_public_key), 143 other => Ok(other), 144 } 145 } 146 } 147 148 #[cfg(feature = "alloc")] 149 impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<SubjectPublicKeyInfo<Params, Key>> for Document 150 where 151 Params: Choice<'a> + Encode, 152 Key: Decode<'a> + Encode + FixedTag, 153 BitStringRef<'a>: From<&'k Key>, 154 { 155 type Error = Error; 156 try_from(spki: SubjectPublicKeyInfo<Params, Key>) -> Result<Document>157 fn try_from(spki: SubjectPublicKeyInfo<Params, Key>) -> Result<Document> { 158 Self::try_from(&spki) 159 } 160 } 161 162 #[cfg(feature = "alloc")] 163 impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<&SubjectPublicKeyInfo<Params, Key>> for Document 164 where 165 Params: Choice<'a> + Encode, 166 Key: Decode<'a> + Encode + FixedTag, 167 BitStringRef<'a>: From<&'k Key>, 168 { 169 type Error = Error; 170 try_from(spki: &SubjectPublicKeyInfo<Params, Key>) -> Result<Document>171 fn try_from(spki: &SubjectPublicKeyInfo<Params, Key>) -> Result<Document> { 172 Ok(Self::encode_msg(spki)?) 173 } 174 } 175 176 #[cfg(feature = "pem")] 177 impl<Params, Key> PemLabel for SubjectPublicKeyInfo<Params, Key> { 178 const PEM_LABEL: &'static str = "PUBLIC KEY"; 179 } 180 181 #[cfg(feature = "alloc")] 182 mod allocating { 183 use super::*; 184 use crate::EncodePublicKey; 185 use der::referenced::*; 186 187 impl<'a> RefToOwned<'a> for SubjectPublicKeyInfoRef<'a> { 188 type Owned = SubjectPublicKeyInfoOwned; ref_to_owned(&self) -> Self::Owned189 fn ref_to_owned(&self) -> Self::Owned { 190 SubjectPublicKeyInfo { 191 algorithm: self.algorithm.ref_to_owned(), 192 subject_public_key: self.subject_public_key.ref_to_owned(), 193 } 194 } 195 } 196 197 impl OwnedToRef for SubjectPublicKeyInfoOwned { 198 type Borrowed<'a> = SubjectPublicKeyInfoRef<'a>; owned_to_ref(&self) -> Self::Borrowed<'_>199 fn owned_to_ref(&self) -> Self::Borrowed<'_> { 200 SubjectPublicKeyInfo { 201 algorithm: self.algorithm.owned_to_ref(), 202 subject_public_key: self.subject_public_key.owned_to_ref(), 203 } 204 } 205 } 206 207 impl SubjectPublicKeyInfoOwned { 208 /// Create a [`SubjectPublicKeyInfoOwned`] from any object that implements 209 /// [`EncodePublicKey`]. from_key<T>(source: T) -> Result<Self> where T: EncodePublicKey,210 pub fn from_key<T>(source: T) -> Result<Self> 211 where 212 T: EncodePublicKey, 213 { 214 Ok(source.to_public_key_der()?.decode_msg::<Self>()?) 215 } 216 } 217 } 218