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