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}