x509_ocsp/cert_status.rs
1//! X.509 OCSP CertStatus
2
3use crate::OcspGeneralizedTime;
4use const_oid::AssociatedOid;
5use core::option::Option;
6use der::{asn1::Null, Choice, Decode, Sequence};
7use x509_cert::{crl::RevokedCert, ext::pkix::CrlReason};
8
9/// CertStatus structure as defined in [RFC 6960 Section 4.2.1].
10///
11/// ```text
12/// CertStatus ::= CHOICE {
13/// good [0] IMPLICIT NULL,
14/// revoked [1] IMPLICIT RevokedInfo,
15/// unknown [2] IMPLICIT UnknownInfo }
16/// ```
17///
18/// [RFC 6960 Section 4.2.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.1
19#[derive(Copy, Clone, Debug, Eq, PartialEq, Choice)]
20#[allow(missing_docs)]
21pub enum CertStatus {
22 #[asn1(context_specific = "0", tag_mode = "IMPLICIT")]
23 Good(Null),
24
25 #[asn1(context_specific = "1", tag_mode = "IMPLICIT", constructed = "true")]
26 Revoked(RevokedInfo),
27
28 #[asn1(context_specific = "2", tag_mode = "IMPLICIT")]
29 Unknown(UnknownInfo),
30}
31
32impl CertStatus {
33 /// Returns `CertStatus` set to `good` as defined in [RFC 6960 Section 4.2.1]
34 ///
35 /// [RFC 6960 Section 4.2.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.1
36 pub fn good() -> Self {
37 Self::Good(Null)
38 }
39
40 /// Returns `CertStatus` set to `revoked` as defined in [RFC 6960 Section 4.2.1]
41 ///
42 /// [RFC 6960 Section 4.2.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.1
43 pub fn revoked(info: impl Into<RevokedInfo>) -> Self {
44 Self::Revoked(info.into())
45 }
46
47 /// Returns `CertStatus` set to `unknown` as defined in [RFC 6960 Section 4.2.1]
48 ///
49 /// [RFC 6960 Section 4.2.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.1
50 pub fn unknown() -> Self {
51 Self::Unknown(Null)
52 }
53}
54
55/// RevokedInfo structure as defined in [RFC 6960 Section 4.2.1].
56///
57/// ```text
58/// RevokedInfo ::= SEQUENCE {
59/// revocationTime GeneralizedTime,
60/// revocationReason [0] EXPLICIT CRLReason OPTIONAL }
61/// ```
62///
63/// [RFC 6960 Section 4.2.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.1
64#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)]
65#[allow(missing_docs)]
66pub struct RevokedInfo {
67 pub revocation_time: OcspGeneralizedTime,
68
69 #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
70 pub revocation_reason: Option<CrlReason>,
71}
72
73/// RevokedInfo structure as defined in [RFC 6960 Section 4.2.1].
74///
75/// ```text
76/// UnknownInfo ::= NULL
77/// ```
78///
79/// [RFC 6960 Section 4.2.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.1
80pub type UnknownInfo = Null;
81
82impl From<&RevokedInfo> for RevokedInfo {
83 fn from(info: &RevokedInfo) -> Self {
84 *info
85 }
86}
87
88impl From<&RevokedCert> for RevokedInfo {
89 /// Converts [`RevokedCert`] to [`RevokedInfo`].
90 ///
91 /// Attempts to extract the [`CrlReason`]. If it fails, the `CrlReason` is set to `None`.
92 fn from(rc: &RevokedCert) -> Self {
93 Self {
94 revocation_time: rc.revocation_date.into(),
95 revocation_reason: match &rc.crl_entry_extensions {
96 Some(extns) => {
97 let mut filter = extns.iter().filter(|extn| extn.extn_id == CrlReason::OID);
98 match filter.next() {
99 Some(extn) => CrlReason::from_der(extn.extn_value.as_bytes()).ok(),
100 None => None,
101 }
102 }
103 None => None,
104 },
105 }
106 }
107}
108
109impl From<RevokedCert> for RevokedInfo {
110 /// Converts [`RevokedCert`] to [`RevokedInfo`].
111 ///
112 /// Attempts to extract the [`CrlReason`]. If it fails, the `CrlReason` is set to `None`.
113 fn from(rc: RevokedCert) -> Self {
114 Self::from(&rc)
115 }
116}