1 use alloc::vec::Vec;
2 
3 use 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 };
6 use const_oid::AssociatedOid;
7 use der::asn1::{GeneralizedTime, ObjectIdentifier};
8 use der::flagset::{flags, FlagSet};
9 use der::Sequence;
10 
11 flags! {
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)]
48 pub struct KeyUsage(pub FlagSet<KeyUsages>);
49 
50 impl AssociatedOid for KeyUsage {
51     const OID: ObjectIdentifier = ID_CE_KEY_USAGE;
52 }
53 
54 impl_newtype!(KeyUsage, FlagSet<KeyUsages>);
55 impl_extension!(KeyUsage, critical = true);
56 
57 impl KeyUsage {
58     /// The subject public key is used for verifying digital signatures
digital_signature(&self) -> bool59     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.
non_repudiation(&self) -> bool65     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.
key_encipherment(&self) -> bool71     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.
data_encipherment(&self) -> bool77     pub fn data_encipherment(&self) -> bool {
78         self.0.contains(KeyUsages::DataEncipherment)
79     }
80 
81     /// The subject public key is used for key agreement
key_agreement(&self) -> bool82     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.
key_cert_sign(&self) -> bool88     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).
crl_sign(&self) -> bool95     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.
encipher_only(&self) -> bool103     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.
decipher_only(&self) -> bool111     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)]
133 pub struct ExtendedKeyUsage(pub Vec<ObjectIdentifier>);
134 
135 impl AssociatedOid for ExtendedKeyUsage {
136     const OID: ObjectIdentifier = ID_CE_EXT_KEY_USAGE;
137 }
138 
139 impl_newtype!(ExtendedKeyUsage, Vec<ObjectIdentifier>);
140 
141 impl crate::ext::AsExtension for ExtendedKeyUsage {
critical( &self, _subject: &crate::name::Name, _extensions: &[crate::ext::Extension], ) -> bool142     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)]
179 pub 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 
187 impl AssociatedOid for PrivateKeyUsagePeriod {
188     const OID: ObjectIdentifier = ID_CE_PRIVATE_KEY_USAGE_PERIOD;
189 }
190 
191 impl_extension!(PrivateKeyUsagePeriod, critical = false);
192 
193 #[cfg(test)]
194 mod tests {
195     use super::*;
196 
197     #[test]
digital_signature_contains_digital_signature()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]
all_contains_digital_signature()204     fn all_contains_digital_signature() {
205         let key_usage = KeyUsage(FlagSet::full());
206         assert!(key_usage.digital_signature());
207     }
208 
209     #[test]
key_encipherment_not_contains_digital_signature()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]
empty_not_contains_digital_signature()216     fn empty_not_contains_digital_signature() {
217         let key_usage = KeyUsage(None.into());
218         assert!(!key_usage.digital_signature());
219     }
220 }
221