x509_parser/
revocation_list.rs

1use crate::error::{X509Error, X509Result};
2use crate::extensions::*;
3use crate::time::ASN1Time;
4use crate::utils::format_serial;
5use crate::x509::{
6    parse_serial, parse_signature_value, AlgorithmIdentifier, ReasonCode, X509Name, X509Version,
7};
8
9#[cfg(feature = "verify")]
10use crate::verify::verify_signature;
11#[cfg(feature = "verify")]
12use crate::x509::SubjectPublicKeyInfo;
13use asn1_rs::{BitString, FromDer};
14use der_parser::der::*;
15use der_parser::num_bigint::BigUint;
16use nom::combinator::{all_consuming, complete, map, opt};
17use nom::multi::many0;
18use nom::Offset;
19use oid_registry::*;
20use std::collections::HashMap;
21
22/// An X.509 v2 Certificate Revocation List (CRL).
23///
24/// X.509 v2 CRLs are defined in [RFC5280](https://tools.ietf.org/html/rfc5280).
25///
26/// # Example
27///
28/// To parse a CRL and print information about revoked certificates:
29///
30/// ```rust
31/// use x509_parser::prelude::FromDer;
32/// use x509_parser::revocation_list::CertificateRevocationList;
33///
34/// # static DER: &'static [u8] = include_bytes!("../assets/example.crl");
35/// #
36/// # fn main() {
37/// let res = CertificateRevocationList::from_der(DER);
38/// match res {
39///     Ok((_rem, crl)) => {
40///         for revoked in crl.iter_revoked_certificates() {
41///             println!("Revoked certificate serial: {}", revoked.raw_serial_as_string());
42///             println!("  Reason: {}", revoked.reason_code().unwrap_or_default().1);
43///         }
44///     },
45///     _ => panic!("CRL parsing failed: {:?}", res),
46/// }
47/// # }
48/// ```
49#[derive(Clone, Debug)]
50pub struct CertificateRevocationList<'a> {
51    pub tbs_cert_list: TbsCertList<'a>,
52    pub signature_algorithm: AlgorithmIdentifier<'a>,
53    pub signature_value: BitString<'a>,
54
55    /// Complete raw ASN.1 DER content (TBS certificate list, signature algorithm and signature).
56    pub(crate) raw: &'a [u8],
57}
58
59impl<'a> CertificateRevocationList<'a> {
60    /// Get the version of the encoded certificate
61    pub fn version(&self) -> Option<X509Version> {
62        self.tbs_cert_list.version
63    }
64
65    /// Get the certificate issuer.
66    #[inline]
67    pub fn issuer(&self) -> &X509Name<'_> {
68        &self.tbs_cert_list.issuer
69    }
70
71    /// Get the date and time of the last (this) update.
72    #[inline]
73    pub fn last_update(&self) -> ASN1Time {
74        self.tbs_cert_list.this_update
75    }
76
77    /// Get the date and time of the next update, if present.
78    #[inline]
79    pub fn next_update(&self) -> Option<ASN1Time> {
80        self.tbs_cert_list.next_update
81    }
82
83    /// Return an iterator over the `RevokedCertificate` objects
84    pub fn iter_revoked_certificates(&self) -> impl Iterator<Item = &RevokedCertificate<'a>> {
85        self.tbs_cert_list.revoked_certificates.iter()
86    }
87
88    /// Get the CRL extensions.
89    #[inline]
90    pub fn extensions(&self) -> &[X509Extension<'_>] {
91        &self.tbs_cert_list.extensions
92    }
93
94    /// Get the CRL number, if present
95    ///
96    /// Note that the returned value is a `BigUint`, because of the following RFC specification:
97    /// <pre>
98    /// Given the requirements above, CRL numbers can be expected to contain long integers.  CRL
99    /// verifiers MUST be able to handle CRLNumber values up to 20 octets.  Conformant CRL issuers
100    /// MUST NOT use CRLNumber values longer than 20 octets.
101    /// </pre>
102    pub fn crl_number(&self) -> Option<&BigUint> {
103        self.extensions()
104            .iter()
105            .find(|&ext| ext.oid == OID_X509_EXT_CRL_NUMBER)
106            .and_then(|ext| match ext.parsed_extension {
107                ParsedExtension::CRLNumber(ref num) => Some(num),
108                _ => None,
109            })
110    }
111
112    /// Verify the cryptographic signature of this certificate revocation list
113    ///
114    /// `public_key` is the public key of the **signer**.
115    ///
116    /// Not all algorithms are supported, this function is limited to what `ring` supports.
117    #[cfg(feature = "verify")]
118    #[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
119    pub fn verify_signature(&self, public_key: &SubjectPublicKeyInfo) -> Result<(), X509Error> {
120        verify_signature(
121            public_key,
122            &self.signature_algorithm,
123            &self.signature_value,
124            self.tbs_cert_list.raw,
125        )
126    }
127
128    ///
129    /// Return the raw ASN.1 DER content of the complete signed certificate revocation list that was parsed.
130    ///
131    /// This includes the to-be-signed (TBS) certificate list, the signature algorithm, and the signature.
132    /// If you want just the ASN.1 DER of the TBS certificate list, prefer [`TbsCertList::as_ref()`].
133    ///
134    /// We avoid the `AsRef` trait in this instance to ensure the full lifetime of the `CertificateRevocationList` is used.
135    pub fn as_raw(&self) -> &'a [u8] {
136        self.raw
137    }
138}
139
140impl<'a> AsRef<[u8]> for CertificateRevocationList<'a> {
141    fn as_ref(&self) -> &[u8] {
142        self.as_raw()
143    }
144}
145
146/// <pre>
147/// CertificateList  ::=  SEQUENCE  {
148///      tbsCertList          TBSCertList,
149///      signatureAlgorithm   AlgorithmIdentifier,
150///      signatureValue       BIT STRING  }
151/// </pre>
152impl<'a> FromDer<'a, X509Error> for CertificateRevocationList<'a> {
153    fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
154        let start_i = i;
155        let (rem, mut crl) = parse_der_sequence_defined_g(|i, _| {
156            let (i, tbs_cert_list) = TbsCertList::from_der(i)?;
157            let (i, signature_algorithm) = AlgorithmIdentifier::from_der(i)?;
158            let (i, signature_value) = parse_signature_value(i)?;
159            let crl = CertificateRevocationList {
160                tbs_cert_list,
161                signature_algorithm,
162                signature_value,
163                raw: &[],
164            };
165            Ok((i, crl))
166        })(i)?;
167        let len = start_i.offset(rem);
168        crl.raw = &start_i[..len];
169        Ok((rem, crl))
170    }
171}
172
173/// The sequence TBSCertList contains information about the certificates that have
174/// been revoked by the CA that issued the CRL.
175///
176/// RFC5280 definition:
177///
178/// <pre>
179/// TBSCertList  ::=  SEQUENCE  {
180///         version                 Version OPTIONAL,
181///                                      -- if present, MUST be v2
182///         signature               AlgorithmIdentifier,
183///         issuer                  Name,
184///         thisUpdate              Time,
185///         nextUpdate              Time OPTIONAL,
186///         revokedCertificates     SEQUENCE OF SEQUENCE  {
187///             userCertificate         CertificateSerialNumber,
188///             revocationDate          Time,
189///             crlEntryExtensions      Extensions OPTIONAL
190///                                      -- if present, version MUST be v2
191///                                   } OPTIONAL,
192///         crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
193///                                      -- if present, version MUST be v2
194///                             }
195/// </pre>
196#[derive(Clone, Debug, PartialEq)]
197pub struct TbsCertList<'a> {
198    pub version: Option<X509Version>,
199    pub signature: AlgorithmIdentifier<'a>,
200    pub issuer: X509Name<'a>,
201    pub this_update: ASN1Time,
202    pub next_update: Option<ASN1Time>,
203    pub revoked_certificates: Vec<RevokedCertificate<'a>>,
204    extensions: Vec<X509Extension<'a>>,
205    pub(crate) raw: &'a [u8],
206}
207
208impl TbsCertList<'_> {
209    /// Returns the certificate extensions
210    #[inline]
211    pub fn extensions(&self) -> &[X509Extension<'_>] {
212        &self.extensions
213    }
214
215    /// Returns an iterator over the certificate extensions
216    #[inline]
217    pub fn iter_extensions(&self) -> impl Iterator<Item = &X509Extension<'_>> {
218        self.extensions.iter()
219    }
220
221    /// Searches for an extension with the given `Oid`.
222    ///
223    /// Note: if there are several extensions with the same `Oid`, the first one is returned.
224    pub fn find_extension(&self, oid: &Oid) -> Option<&X509Extension<'_>> {
225        self.extensions.iter().find(|&ext| ext.oid == *oid)
226    }
227
228    /// Builds and returns a map of extensions.
229    ///
230    /// If an extension is present twice, this will fail and return `DuplicateExtensions`.
231    pub fn extensions_map(&self) -> Result<HashMap<Oid<'_>, &X509Extension<'_>>, X509Error> {
232        self.extensions
233            .iter()
234            .try_fold(HashMap::new(), |mut m, ext| {
235                if m.contains_key(&ext.oid) {
236                    return Err(X509Error::DuplicateExtensions);
237                }
238                m.insert(ext.oid.clone(), ext);
239                Ok(m)
240            })
241    }
242}
243
244impl AsRef<[u8]> for TbsCertList<'_> {
245    fn as_ref(&self) -> &[u8] {
246        self.raw
247    }
248}
249
250impl<'a> FromDer<'a, X509Error> for TbsCertList<'a> {
251    fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
252        let start_i = i;
253        parse_der_sequence_defined_g(move |i, _| {
254            let (i, version) =
255                opt(map(parse_der_u32, X509Version))(i).or(Err(X509Error::InvalidVersion))?;
256            let (i, signature) = AlgorithmIdentifier::from_der(i)?;
257            let (i, issuer) = X509Name::from_der(i)?;
258            let (i, this_update) = ASN1Time::from_der(i)?;
259            let (i, next_update) = ASN1Time::from_der_opt(i)?;
260            let (i, revoked_certificates) = opt(complete(parse_revoked_certificates))(i)?;
261            let (i, extensions) = parse_extensions(i, Tag(0))?;
262            let len = start_i.offset(i);
263            let tbs = TbsCertList {
264                version,
265                signature,
266                issuer,
267                this_update,
268                next_update,
269                revoked_certificates: revoked_certificates.unwrap_or_default(),
270                extensions,
271                raw: &start_i[..len],
272            };
273            Ok((i, tbs))
274        })(i)
275    }
276}
277
278#[derive(Clone, Debug, PartialEq)]
279pub struct RevokedCertificate<'a> {
280    /// The Serial number of the revoked certificate
281    pub user_certificate: BigUint,
282    /// The date on which the revocation occurred is specified.
283    pub revocation_date: ASN1Time,
284    /// Additional information about revocation
285    extensions: Vec<X509Extension<'a>>,
286    pub(crate) raw_serial: &'a [u8],
287}
288
289impl RevokedCertificate<'_> {
290    /// Return the serial number of the revoked certificate
291    pub fn serial(&self) -> &BigUint {
292        &self.user_certificate
293    }
294
295    /// Get the CRL entry extensions.
296    #[inline]
297    pub fn extensions(&self) -> &[X509Extension<'_>] {
298        &self.extensions
299    }
300
301    /// Returns an iterator over the CRL entry extensions
302    #[inline]
303    pub fn iter_extensions(&self) -> impl Iterator<Item = &X509Extension<'_>> {
304        self.extensions.iter()
305    }
306
307    /// Searches for a CRL entry extension with the given `Oid`.
308    ///
309    /// Note: if there are several extensions with the same `Oid`, the first one is returned.
310    pub fn find_extension(&self, oid: &Oid) -> Option<&X509Extension<'_>> {
311        self.extensions.iter().find(|&ext| ext.oid == *oid)
312    }
313
314    /// Builds and returns a map of CRL entry extensions.
315    ///
316    /// If an extension is present twice, this will fail and return `DuplicateExtensions`.
317    pub fn extensions_map(&self) -> Result<HashMap<Oid<'_>, &X509Extension<'_>>, X509Error> {
318        self.extensions
319            .iter()
320            .try_fold(HashMap::new(), |mut m, ext| {
321                if m.contains_key(&ext.oid) {
322                    return Err(X509Error::DuplicateExtensions);
323                }
324                m.insert(ext.oid.clone(), ext);
325                Ok(m)
326            })
327    }
328
329    /// Get the raw bytes of the certificate serial number
330    pub fn raw_serial(&self) -> &[u8] {
331        self.raw_serial
332    }
333
334    /// Get a formatted string of the certificate serial number, separated by ':'
335    pub fn raw_serial_as_string(&self) -> String {
336        format_serial(self.raw_serial)
337    }
338
339    /// Get the code identifying the reason for the revocation, if present
340    pub fn reason_code(&self) -> Option<(bool, ReasonCode)> {
341        self.find_extension(&OID_X509_EXT_REASON_CODE)
342            .and_then(|ext| match ext.parsed_extension {
343                ParsedExtension::ReasonCode(code) => Some((ext.critical, code)),
344                _ => None,
345            })
346    }
347
348    /// Get the invalidity date, if present
349    ///
350    /// The invalidity date is the date on which it is known or suspected that the private
351    ///  key was compromised or that the certificate otherwise became invalid.
352    pub fn invalidity_date(&self) -> Option<(bool, ASN1Time)> {
353        self.find_extension(&OID_X509_EXT_INVALIDITY_DATE)
354            .and_then(|ext| match ext.parsed_extension {
355                ParsedExtension::InvalidityDate(date) => Some((ext.critical, date)),
356                _ => None,
357            })
358    }
359}
360
361// revokedCertificates     SEQUENCE OF SEQUENCE  {
362//     userCertificate         CertificateSerialNumber,
363//     revocationDate          Time,
364//     crlEntryExtensions      Extensions OPTIONAL
365//                                   -- if present, MUST be v2
366//                          }  OPTIONAL,
367impl<'a> FromDer<'a, X509Error> for RevokedCertificate<'a> {
368    fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
369        parse_der_sequence_defined_g(|i, _| {
370            let (i, (raw_serial, user_certificate)) = parse_serial(i)?;
371            let (i, revocation_date) = ASN1Time::from_der(i)?;
372            let (i, extensions) = opt(complete(parse_extension_sequence))(i)?;
373            let revoked = RevokedCertificate {
374                user_certificate,
375                revocation_date,
376                extensions: extensions.unwrap_or_default(),
377                raw_serial,
378            };
379            Ok((i, revoked))
380        })(i)
381    }
382}
383
384fn parse_revoked_certificates(i: &[u8]) -> X509Result<'_, Vec<RevokedCertificate<'_>>> {
385    parse_der_sequence_defined_g(|a, _| {
386        all_consuming(many0(complete(RevokedCertificate::from_der)))(a)
387    })(i)
388}