x509_cert/ext/pkix/
keyusage.rs

1use alloc::vec::Vec;
2
3use const_oid::db::rfc5280::{
4    ANY_EXTENDED_KEY_USAGE, ID_CE_EXT_KEY_USAGE, ID_CE_KEY_USAGE, ID_CE_PRIVATE_KEY_USAGE_PERIOD,
5};
6use const_oid::AssociatedOid;
7use der::asn1::{GeneralizedTime, ObjectIdentifier};
8use der::flagset::{flags, FlagSet};
9use der::Sequence;
10
11flags! {
12    /// Key usage flags as defined in [RFC 5280 Section 4.2.1.3].
13    ///
14    /// ```text
15    /// KeyUsage ::= BIT STRING {
16    ///      digitalSignature        (0),
17    ///      nonRepudiation          (1),  -- recent editions of X.509 have
18    ///                                    -- renamed this bit to contentCommitment
19    ///      keyEncipherment         (2),
20    ///      dataEncipherment        (3),
21    ///      keyAgreement            (4),
22    ///      keyCertSign             (5),
23    ///      cRLSign                 (6),
24    ///      encipherOnly            (7),
25    ///      decipherOnly            (8)
26    /// }
27    /// ```
28    ///
29    /// [RFC 5280 Section 4.2.1.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3
30    #[allow(missing_docs)]
31    pub enum KeyUsages: u16 {
32        DigitalSignature = 1 << 0,
33        NonRepudiation = 1 << 1,
34        KeyEncipherment = 1 << 2,
35        DataEncipherment = 1 << 3,
36        KeyAgreement = 1 << 4,
37        KeyCertSign = 1 << 5,
38        CRLSign = 1 << 6,
39        EncipherOnly = 1 << 7,
40        DecipherOnly = 1 << 8,
41    }
42}
43
44/// KeyUsage as defined in [RFC 5280 Section 4.2.1.3].
45///
46/// [RFC 5280 Section 4.2.1.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3
47#[derive(Copy, Clone, Debug, PartialEq, Eq)]
48pub struct KeyUsage(pub FlagSet<KeyUsages>);
49
50impl AssociatedOid for KeyUsage {
51    const OID: ObjectIdentifier = ID_CE_KEY_USAGE;
52}
53
54impl_newtype!(KeyUsage, FlagSet<KeyUsages>);
55impl_extension!(KeyUsage, critical = true);
56
57impl KeyUsage {
58    /// The subject public key is used for verifying digital signatures
59    pub fn digital_signature(&self) -> bool {
60        self.0.contains(KeyUsages::DigitalSignature)
61    }
62
63    /// When the subject public key is used to verify digital signatures,
64    /// it is asserted as non-repudiation.
65    pub fn non_repudiation(&self) -> bool {
66        self.0.contains(KeyUsages::NonRepudiation)
67    }
68
69    /// The subject public key is used for enciphering private or
70    /// secret keys, i.e., for key transport.
71    pub fn key_encipherment(&self) -> bool {
72        self.0.contains(KeyUsages::KeyEncipherment)
73    }
74
75    /// The subject public key is used for directly enciphering
76    /// raw user data without the use of an intermediate symmetric cipher.
77    pub fn data_encipherment(&self) -> bool {
78        self.0.contains(KeyUsages::DataEncipherment)
79    }
80
81    /// The subject public key is used for key agreement
82    pub fn key_agreement(&self) -> bool {
83        self.0.contains(KeyUsages::KeyAgreement)
84    }
85
86    /// The subject public key is used for enciphering private or
87    /// secret keys, i.e., for key transport.
88    pub fn key_cert_sign(&self) -> bool {
89        self.0.contains(KeyUsages::KeyCertSign)
90    }
91
92    /// The subject public key is used for verifying signatures
93    /// on certificate revocation lists (e.g., CRLs, delta CRLs,
94    /// or ARLs).
95    pub fn crl_sign(&self) -> bool {
96        self.0.contains(KeyUsages::CRLSign)
97    }
98
99    /// The meaning of the `encipher_only` is undefined when `key_agreement`
100    /// returns false.  When `encipher_only` returns true and
101    /// `key_agreement` also returns true, the subject public key may be
102    /// used only for enciphering data while performing key agreement.
103    pub fn encipher_only(&self) -> bool {
104        self.0.contains(KeyUsages::EncipherOnly)
105    }
106
107    /// The meaning of the `decipher_only` is undefined when `key_agreement`
108    /// returns false.  When `encipher_only` returns true and
109    /// `key_agreement` also returns true, the subject public key may be
110    /// used only for deciphering data while performing key agreement.
111    pub fn decipher_only(&self) -> bool {
112        self.0.contains(KeyUsages::DecipherOnly)
113    }
114}
115
116/// ExtKeyUsageSyntax as defined in [RFC 5280 Section 4.2.1.12].
117///
118/// Many extended key usage values include:
119/// - [`PKIX_CE_ANYEXTENDEDKEYUSAGE`](constant.PKIX_CE_ANYEXTENDEDKEYUSAGE.html),
120/// - [`PKIX_KP_SERVERAUTH`](constant.PKIX_KP_SERVERAUTH.html),
121/// - [`PKIX_KP_CLIENTAUTH`](constant.PKIX_KP_CLIENTAUTH.html),
122/// - [`PKIX_KP_CODESIGNING`](constant.PKIX_KP_CODESIGNING.html),
123/// - [`PKIX_KP_EMAILPROTECTION`](constant.PKIX_KP_EMAILPROTECTION.html),
124/// - [`PKIX_KP_TIMESTAMPING`](constant.PKIX_KP_TIMESTAMPING.html),
125///
126/// ```text
127/// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
128/// KeyPurposeId ::= OBJECT IDENTIFIER
129/// ```
130///
131/// [RFC 5280 Section 4.2.1.12]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12
132#[derive(Clone, Debug, PartialEq, Eq)]
133pub struct ExtendedKeyUsage(pub Vec<ObjectIdentifier>);
134
135impl AssociatedOid for ExtendedKeyUsage {
136    const OID: ObjectIdentifier = ID_CE_EXT_KEY_USAGE;
137}
138
139impl_newtype!(ExtendedKeyUsage, Vec<ObjectIdentifier>);
140
141impl crate::ext::AsExtension for ExtendedKeyUsage {
142    fn critical(
143        &self,
144        _subject: &crate::name::Name,
145        _extensions: &[crate::ext::Extension],
146    ) -> bool {
147        // https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12
148        //   This extension MAY, at the option of the certificate issuer, be
149        //   either critical or non-critical.
150        //
151        //   If a CA includes extended key usages to satisfy such applications,
152        //   but does not wish to restrict usages of the key, the CA can include
153        //   the special KeyPurposeId anyExtendedKeyUsage in addition to the
154        //   particular key purposes required by the applications.  Conforming CAs
155        //   SHOULD NOT mark this extension as critical if the anyExtendedKeyUsage
156        //   KeyPurposeId is present.  Applications that require the presence of a
157        //   particular purpose MAY reject certificates that include the
158        //   anyExtendedKeyUsage OID but not the particular OID expected for the
159        //   application.
160
161        !self.0.iter().any(|el| *el == ANY_EXTENDED_KEY_USAGE)
162    }
163}
164
165/// PrivateKeyUsagePeriod as defined in [RFC 3280 Section 4.2.1.4].
166///
167/// RFC 5280 states "use of this ISO standard extension is neither deprecated nor recommended for use in the Internet PKI."
168///
169/// ```text
170/// PrivateKeyUsagePeriod ::= SEQUENCE {
171///      notBefore       [0]     GeneralizedTime OPTIONAL,
172///      notAfter        [1]     GeneralizedTime OPTIONAL }
173///      -- either notBefore or notAfter MUST be present
174/// ```
175///
176/// [RFC 3280 Section 4.2.1.12]: https://datatracker.ietf.org/doc/html/rfc3280#section-4.2.1.4
177#[derive(Clone, Debug, PartialEq, Eq, Sequence)]
178#[allow(missing_docs)]
179pub struct PrivateKeyUsagePeriod {
180    #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")]
181    pub not_before: Option<GeneralizedTime>,
182
183    #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")]
184    pub not_after: Option<GeneralizedTime>,
185}
186
187impl AssociatedOid for PrivateKeyUsagePeriod {
188    const OID: ObjectIdentifier = ID_CE_PRIVATE_KEY_USAGE_PERIOD;
189}
190
191impl_extension!(PrivateKeyUsagePeriod, critical = false);
192
193#[cfg(test)]
194mod tests {
195    use super::*;
196
197    #[test]
198    fn digital_signature_contains_digital_signature() {
199        let key_usage = KeyUsage(KeyUsages::DigitalSignature.into());
200        assert!(key_usage.digital_signature());
201    }
202
203    #[test]
204    fn all_contains_digital_signature() {
205        let key_usage = KeyUsage(FlagSet::full());
206        assert!(key_usage.digital_signature());
207    }
208
209    #[test]
210    fn key_encipherment_not_contains_digital_signature() {
211        let key_usage = KeyUsage(KeyUsages::KeyEncipherment.into());
212        assert!(!key_usage.digital_signature());
213    }
214
215    #[test]
216    fn empty_not_contains_digital_signature() {
217        let key_usage = KeyUsage(None.into());
218        assert!(!key_usage.digital_signature());
219    }
220}