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