1 //! Certificate types 2 3 use crate::{name::Name, serial_number::SerialNumber, time::Validity}; 4 use alloc::vec::Vec; 5 use const_oid::AssociatedOid; 6 use core::{cmp::Ordering, fmt::Debug}; 7 use der::asn1::BitString; 8 use der::{Decode, Enumerated, Error, ErrorKind, Sequence, Tag, ValueOrd}; 9 use spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned}; 10 11 #[cfg(feature = "pem")] 12 use der::{ 13 pem::{self, PemLabel}, 14 DecodePem, 15 }; 16 17 /// [`Profile`] allows the consumer of this crate to customize the behavior when parsing 18 /// certificates. 19 /// By default, parsing will be made in a rfc5280-compliant manner. 20 pub trait Profile: PartialEq + Debug + Eq + Clone { 21 /// Checks to run when parsing serial numbers check_serial_number(serial: &SerialNumber<Self>) -> der::Result<()>22 fn check_serial_number(serial: &SerialNumber<Self>) -> der::Result<()> { 23 // See the note in `SerialNumber::new`: we permit lengths of 21 bytes here, 24 // since some X.509 implementations interpret the limit of 20 bytes to refer 25 // to the pre-encoded value. 26 if serial.inner.len() > SerialNumber::<Self>::MAX_DECODE_LEN { 27 Err(Tag::Integer.value_error()) 28 } else { 29 Ok(()) 30 } 31 } 32 } 33 34 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 35 #[derive(Debug, PartialEq, Eq, Clone)] 36 /// Parse certificates with rfc5280-compliant checks 37 pub struct Rfc5280; 38 39 impl Profile for Rfc5280 {} 40 41 #[cfg(feature = "hazmat")] 42 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 43 #[derive(Debug, PartialEq, Eq, Clone)] 44 /// Parse raw x509 certificate and disable all the checks 45 pub struct Raw; 46 47 #[cfg(feature = "hazmat")] 48 impl Profile for Raw { check_serial_number(_serial: &SerialNumber<Self>) -> der::Result<()>49 fn check_serial_number(_serial: &SerialNumber<Self>) -> der::Result<()> { 50 Ok(()) 51 } 52 } 53 54 /// Certificate `Version` as defined in [RFC 5280 Section 4.1]. 55 /// 56 /// ```text 57 /// Version ::= INTEGER { v1(0), v2(1), v3(2) } 58 /// ``` 59 /// 60 /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 61 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 62 #[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)] 63 #[asn1(type = "INTEGER")] 64 #[repr(u8)] 65 pub enum Version { 66 /// Version 1 (default) 67 V1 = 0, 68 69 /// Version 2 70 V2 = 1, 71 72 /// Version 3 73 V3 = 2, 74 } 75 76 impl ValueOrd for Version { value_cmp(&self, other: &Self) -> der::Result<Ordering>77 fn value_cmp(&self, other: &Self) -> der::Result<Ordering> { 78 (*self as u8).value_cmp(&(*other as u8)) 79 } 80 } 81 82 impl Default for Version { default() -> Self83 fn default() -> Self { 84 Self::V1 85 } 86 } 87 88 /// X.509 `TbsCertificate` as defined in [RFC 5280 Section 4.1] 89 pub type TbsCertificate = TbsCertificateInner<Rfc5280>; 90 91 /// X.509 `TbsCertificate` as defined in [RFC 5280 Section 4.1] 92 /// 93 /// ASN.1 structure containing the names of the subject and issuer, a public 94 /// key associated with the subject, a validity period, and other associated 95 /// information. 96 /// 97 /// ```text 98 /// TBSCertificate ::= SEQUENCE { 99 /// version [0] EXPLICIT Version DEFAULT v1, 100 /// serialNumber CertificateSerialNumber, 101 /// signature AlgorithmIdentifier, 102 /// issuer Name, 103 /// validity Validity, 104 /// subject Name, 105 /// subjectPublicKeyInfo SubjectPublicKeyInfo, 106 /// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 107 /// -- If present, version MUST be v2 or v3 108 /// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 109 /// -- If present, version MUST be v2 or v3 110 /// extensions [3] Extensions OPTIONAL 111 /// -- If present, version MUST be v3 -- 112 /// } 113 /// ``` 114 /// 115 /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 116 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 117 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] 118 #[allow(missing_docs)] 119 pub struct TbsCertificateInner<P: Profile = Rfc5280> { 120 /// The certificate version 121 /// 122 /// Note that this value defaults to Version 1 per the RFC. However, 123 /// fields such as `issuer_unique_id`, `subject_unique_id` and `extensions` 124 /// require later versions. Care should be taken in order to ensure 125 /// standards compliance. 126 #[asn1(context_specific = "0", default = "Default::default")] 127 pub version: Version, 128 129 pub serial_number: SerialNumber<P>, 130 pub signature: AlgorithmIdentifierOwned, 131 pub issuer: Name, 132 pub validity: Validity, 133 pub subject: Name, 134 pub subject_public_key_info: SubjectPublicKeyInfoOwned, 135 136 #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] 137 pub issuer_unique_id: Option<BitString>, 138 139 #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] 140 pub subject_unique_id: Option<BitString>, 141 142 #[asn1(context_specific = "3", tag_mode = "EXPLICIT", optional = "true")] 143 pub extensions: Option<crate::ext::Extensions>, 144 } 145 146 impl<P: Profile> TbsCertificateInner<P> { 147 /// Decodes a single extension 148 /// 149 /// Returns an error if multiple of these extensions is present. Returns 150 /// `Ok(None)` if the extension is not present. Returns a decoding error 151 /// if decoding failed. Otherwise returns the extension. get<'a, T: Decode<'a> + AssociatedOid>(&'a self) -> Result<Option<(bool, T)>, Error>152 pub fn get<'a, T: Decode<'a> + AssociatedOid>(&'a self) -> Result<Option<(bool, T)>, Error> { 153 let mut iter = self.filter::<T>().peekable(); 154 match iter.next() { 155 None => Ok(None), 156 Some(item) => match iter.peek() { 157 Some(..) => Err(ErrorKind::Failed.into()), 158 None => Ok(Some(item?)), 159 }, 160 } 161 } 162 163 /// Filters extensions by an associated OID 164 /// 165 /// Returns a filtered iterator over all the extensions with the OID. filter<'a, T: Decode<'a> + AssociatedOid>( &'a self, ) -> impl 'a + Iterator<Item = Result<(bool, T), Error>>166 pub fn filter<'a, T: Decode<'a> + AssociatedOid>( 167 &'a self, 168 ) -> impl 'a + Iterator<Item = Result<(bool, T), Error>> { 169 self.extensions 170 .as_deref() 171 .unwrap_or(&[]) 172 .iter() 173 .filter(|e| e.extn_id == T::OID) 174 .map(|e| Ok((e.critical, T::from_der(e.extn_value.as_bytes())?))) 175 } 176 } 177 178 /// X.509 certificates are defined in [RFC 5280 Section 4.1]. 179 /// 180 /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 181 pub type Certificate = CertificateInner<Rfc5280>; 182 183 /// X.509 certificates are defined in [RFC 5280 Section 4.1]. 184 /// 185 /// ```text 186 /// Certificate ::= SEQUENCE { 187 /// tbsCertificate TBSCertificate, 188 /// signatureAlgorithm AlgorithmIdentifier, 189 /// signature BIT STRING 190 /// } 191 /// ``` 192 /// 193 /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 194 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 195 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] 196 #[allow(missing_docs)] 197 pub struct CertificateInner<P: Profile = Rfc5280> { 198 pub tbs_certificate: TbsCertificateInner<P>, 199 pub signature_algorithm: AlgorithmIdentifierOwned, 200 pub signature: BitString, 201 } 202 203 #[cfg(feature = "pem")] 204 impl<P: Profile> PemLabel for CertificateInner<P> { 205 const PEM_LABEL: &'static str = "CERTIFICATE"; 206 } 207 208 /// `PkiPath` as defined by X.509 and referenced by [RFC 6066]. 209 /// 210 /// This contains a series of certificates in validation order from the 211 /// top-most certificate to the bottom-most certificate. This means that 212 /// the first certificate signs the second certificate and so on. 213 /// 214 /// ```text 215 /// PkiPath ::= SEQUENCE OF Certificate 216 /// ``` 217 /// 218 /// [RFC 6066]: https://datatracker.ietf.org/doc/html/rfc6066#section-10.1 219 pub type PkiPath = Vec<Certificate>; 220 221 #[cfg(feature = "pem")] 222 impl<P: Profile> CertificateInner<P> { 223 /// Parse a chain of pem-encoded certificates from a slice. 224 /// 225 /// Returns the list of certificates. load_pem_chain(mut input: &[u8]) -> Result<Vec<Self>, Error>226 pub fn load_pem_chain(mut input: &[u8]) -> Result<Vec<Self>, Error> { 227 fn find_boundary<T>(haystack: &[T], needle: &[T]) -> Option<usize> 228 where 229 for<'a> &'a [T]: PartialEq, 230 { 231 haystack 232 .windows(needle.len()) 233 .position(|window| window == needle) 234 } 235 236 let mut certs = Vec::new(); 237 let mut position: usize = 0; 238 239 let end_boundary = &b"-----END CERTIFICATE-----"[..]; 240 241 // Strip the trailing whitespaces 242 loop { 243 if input.is_empty() { 244 break; 245 } 246 let last_pos = input.len() - 1; 247 248 match input.get(last_pos) { 249 Some(b'\r') | Some(b'\n') => { 250 input = &input[..last_pos]; 251 } 252 _ => break, 253 } 254 } 255 256 while position < input.len() - 1 { 257 let rest = &input[position..]; 258 let end_pos = find_boundary(rest, end_boundary) 259 .ok_or(pem::Error::PostEncapsulationBoundary)? 260 + end_boundary.len(); 261 262 let cert_buf = &rest[..end_pos]; 263 let cert = Self::from_pem(cert_buf)?; 264 certs.push(cert); 265 266 position += end_pos; 267 } 268 269 Ok(certs) 270 } 271 } 272