boring_imp/x509/
extension.rs

1//! Add extensions to an `X509` certificate or certificate request.
2//!
3//! The extensions defined for X.509 v3 certificates provide methods for
4//! associating additional attributes with users or public keys and for
5//! managing relationships between CAs. The extensions created using this
6//! module can be used with `X509v3Context` objects.
7//!
8//! # Example
9//!
10//! ```rust
11//! use boring::x509::extension::BasicConstraints;
12//! use boring::x509::X509Extension;
13//!
14//! let mut bc = BasicConstraints::new();
15//! let bc = bc.critical().ca().pathlen(1);
16//! let extension: X509Extension = bc.build().unwrap();
17//! ```
18use std::fmt::Write;
19
20use crate::asn1::Asn1Object;
21use crate::error::ErrorStack;
22use crate::nid::Nid;
23use crate::x509::{GeneralName, Stack, X509Extension, X509v3Context};
24use foreign_types::ForeignType;
25
26/// An extension which indicates whether a certificate is a CA certificate.
27pub struct BasicConstraints {
28    critical: bool,
29    ca: bool,
30    pathlen: Option<u32>,
31}
32
33impl Default for BasicConstraints {
34    fn default() -> BasicConstraints {
35        BasicConstraints::new()
36    }
37}
38
39impl BasicConstraints {
40    /// Construct a new `BasicConstraints` extension.
41    pub fn new() -> BasicConstraints {
42        BasicConstraints {
43            critical: false,
44            ca: false,
45            pathlen: None,
46        }
47    }
48
49    /// Sets the `critical` flag to `true`. The extension will be critical.
50    pub fn critical(&mut self) -> &mut BasicConstraints {
51        self.critical = true;
52        self
53    }
54
55    /// Sets the `ca` flag to `true`.
56    pub fn ca(&mut self) -> &mut BasicConstraints {
57        self.ca = true;
58        self
59    }
60
61    /// Sets the pathlen to an optional non-negative value. The pathlen is the
62    /// maximum number of CAs that can appear below this one in a chain.
63    pub fn pathlen(&mut self, pathlen: u32) -> &mut BasicConstraints {
64        self.pathlen = Some(pathlen);
65        self
66    }
67
68    /// Return the `BasicConstraints` extension as an `X509Extension`.
69    pub fn build(&self) -> Result<X509Extension, ErrorStack> {
70        let mut value = String::new();
71        if self.critical {
72            value.push_str("critical,");
73        }
74        value.push_str("CA:");
75        if self.ca {
76            value.push_str("TRUE");
77        } else {
78            value.push_str("FALSE");
79        }
80        if let Some(pathlen) = self.pathlen {
81            write!(value, ",pathlen:{}", pathlen).unwrap();
82        }
83        X509Extension::new_nid(None, None, Nid::BASIC_CONSTRAINTS, &value)
84    }
85}
86
87/// An extension consisting of a list of names of the permitted key usages.
88pub struct KeyUsage {
89    critical: bool,
90    digital_signature: bool,
91    non_repudiation: bool,
92    key_encipherment: bool,
93    data_encipherment: bool,
94    key_agreement: bool,
95    key_cert_sign: bool,
96    crl_sign: bool,
97    encipher_only: bool,
98    decipher_only: bool,
99}
100
101impl Default for KeyUsage {
102    fn default() -> KeyUsage {
103        KeyUsage::new()
104    }
105}
106
107impl KeyUsage {
108    /// Construct a new `KeyUsage` extension.
109    pub fn new() -> KeyUsage {
110        KeyUsage {
111            critical: false,
112            digital_signature: false,
113            non_repudiation: false,
114            key_encipherment: false,
115            data_encipherment: false,
116            key_agreement: false,
117            key_cert_sign: false,
118            crl_sign: false,
119            encipher_only: false,
120            decipher_only: false,
121        }
122    }
123
124    /// Sets the `critical` flag to `true`. The extension will be critical.
125    pub fn critical(&mut self) -> &mut KeyUsage {
126        self.critical = true;
127        self
128    }
129
130    /// Sets the `digitalSignature` flag to `true`.
131    pub fn digital_signature(&mut self) -> &mut KeyUsage {
132        self.digital_signature = true;
133        self
134    }
135
136    /// Sets the `nonRepudiation` flag to `true`.
137    pub fn non_repudiation(&mut self) -> &mut KeyUsage {
138        self.non_repudiation = true;
139        self
140    }
141
142    /// Sets the `keyEncipherment` flag to `true`.
143    pub fn key_encipherment(&mut self) -> &mut KeyUsage {
144        self.key_encipherment = true;
145        self
146    }
147
148    /// Sets the `dataEncipherment` flag to `true`.
149    pub fn data_encipherment(&mut self) -> &mut KeyUsage {
150        self.data_encipherment = true;
151        self
152    }
153
154    /// Sets the `keyAgreement` flag to `true`.
155    pub fn key_agreement(&mut self) -> &mut KeyUsage {
156        self.key_agreement = true;
157        self
158    }
159
160    /// Sets the `keyCertSign` flag to `true`.
161    pub fn key_cert_sign(&mut self) -> &mut KeyUsage {
162        self.key_cert_sign = true;
163        self
164    }
165
166    /// Sets the `cRLSign` flag to `true`.
167    pub fn crl_sign(&mut self) -> &mut KeyUsage {
168        self.crl_sign = true;
169        self
170    }
171
172    /// Sets the `encipherOnly` flag to `true`.
173    pub fn encipher_only(&mut self) -> &mut KeyUsage {
174        self.encipher_only = true;
175        self
176    }
177
178    /// Sets the `decipherOnly` flag to `true`.
179    pub fn decipher_only(&mut self) -> &mut KeyUsage {
180        self.decipher_only = true;
181        self
182    }
183
184    /// Return the `KeyUsage` extension as an `X509Extension`.
185    pub fn build(&self) -> Result<X509Extension, ErrorStack> {
186        let mut value = String::new();
187        let mut first = true;
188        append(&mut value, &mut first, self.critical, "critical");
189        append(
190            &mut value,
191            &mut first,
192            self.digital_signature,
193            "digitalSignature",
194        );
195        append(
196            &mut value,
197            &mut first,
198            self.non_repudiation,
199            "nonRepudiation",
200        );
201        append(
202            &mut value,
203            &mut first,
204            self.key_encipherment,
205            "keyEncipherment",
206        );
207        append(
208            &mut value,
209            &mut first,
210            self.data_encipherment,
211            "dataEncipherment",
212        );
213        append(&mut value, &mut first, self.key_agreement, "keyAgreement");
214        append(&mut value, &mut first, self.key_cert_sign, "keyCertSign");
215        append(&mut value, &mut first, self.crl_sign, "cRLSign");
216        append(&mut value, &mut first, self.encipher_only, "encipherOnly");
217        append(&mut value, &mut first, self.decipher_only, "decipherOnly");
218        X509Extension::new_nid(None, None, Nid::KEY_USAGE, &value)
219    }
220}
221
222/// An extension consisting of a list of usages indicating purposes
223/// for which the certificate public key can be used for.
224pub struct ExtendedKeyUsage {
225    critical: bool,
226    items: Vec<String>,
227}
228
229impl Default for ExtendedKeyUsage {
230    fn default() -> ExtendedKeyUsage {
231        ExtendedKeyUsage::new()
232    }
233}
234
235impl ExtendedKeyUsage {
236    /// Construct a new `ExtendedKeyUsage` extension.
237    pub fn new() -> ExtendedKeyUsage {
238        ExtendedKeyUsage {
239            critical: false,
240            items: vec![],
241        }
242    }
243
244    /// Sets the `critical` flag to `true`. The extension will be critical.
245    pub fn critical(&mut self) -> &mut ExtendedKeyUsage {
246        self.critical = true;
247        self
248    }
249
250    /// Sets the `serverAuth` flag to `true`.
251    pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage {
252        self.other("serverAuth")
253    }
254
255    /// Sets the `clientAuth` flag to `true`.
256    pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage {
257        self.other("clientAuth")
258    }
259
260    /// Sets the `codeSigning` flag to `true`.
261    pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage {
262        self.other("codeSigning")
263    }
264
265    /// Sets the `timeStamping` flag to `true`.
266    pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage {
267        self.other("timeStamping")
268    }
269
270    /// Sets the `msCodeInd` flag to `true`.
271    pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage {
272        self.other("msCodeInd")
273    }
274
275    /// Sets the `msCodeCom` flag to `true`.
276    pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage {
277        self.other("msCodeCom")
278    }
279
280    /// Sets the `msCTLSign` flag to `true`.
281    pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage {
282        self.other("msCTLSign")
283    }
284
285    /// Sets the `msSGC` flag to `true`.
286    pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage {
287        self.other("msSGC")
288    }
289
290    /// Sets the `msEFS` flag to `true`.
291    pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage {
292        self.other("msEFS")
293    }
294
295    /// Sets the `nsSGC` flag to `true`.
296    pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage {
297        self.other("nsSGC")
298    }
299
300    /// Sets a flag not already defined.
301    pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage {
302        self.items.push(other.to_string());
303        self
304    }
305
306    /// Return the `ExtendedKeyUsage` extension as an `X509Extension`.
307    pub fn build(&self) -> Result<X509Extension, ErrorStack> {
308        let mut stack = Stack::new()?;
309        for item in &self.items {
310            stack.push(Asn1Object::from_str(item)?)?;
311        }
312        unsafe {
313            X509Extension::new_internal(Nid::EXT_KEY_USAGE, self.critical, stack.as_ptr().cast())
314        }
315    }
316}
317
318/// An extension that provides a means of identifying certificates that contain a
319/// particular public key.
320pub struct SubjectKeyIdentifier {
321    critical: bool,
322}
323
324impl Default for SubjectKeyIdentifier {
325    fn default() -> SubjectKeyIdentifier {
326        SubjectKeyIdentifier::new()
327    }
328}
329
330impl SubjectKeyIdentifier {
331    /// Construct a new `SubjectKeyIdentifier` extension.
332    pub fn new() -> SubjectKeyIdentifier {
333        SubjectKeyIdentifier { critical: false }
334    }
335
336    /// Sets the `critical` flag to `true`. The extension will be critical.
337    pub fn critical(&mut self) -> &mut SubjectKeyIdentifier {
338        self.critical = true;
339        self
340    }
341
342    /// Return a `SubjectKeyIdentifier` extension as an `X509Extension`.
343    pub fn build(&self, ctx: &X509v3Context) -> Result<X509Extension, ErrorStack> {
344        let mut value = String::new();
345        let mut first = true;
346        append(&mut value, &mut first, self.critical, "critical");
347        append(&mut value, &mut first, true, "hash");
348        X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_KEY_IDENTIFIER, &value)
349    }
350}
351
352/// An extension that provides a means of identifying the public key corresponding
353/// to the private key used to sign a CRL.
354pub struct AuthorityKeyIdentifier {
355    critical: bool,
356    keyid: Option<bool>,
357    issuer: Option<bool>,
358}
359
360impl Default for AuthorityKeyIdentifier {
361    fn default() -> AuthorityKeyIdentifier {
362        AuthorityKeyIdentifier::new()
363    }
364}
365
366impl AuthorityKeyIdentifier {
367    /// Construct a new `AuthorityKeyIdentifier` extension.
368    pub fn new() -> AuthorityKeyIdentifier {
369        AuthorityKeyIdentifier {
370            critical: false,
371            keyid: None,
372            issuer: None,
373        }
374    }
375
376    /// Sets the `critical` flag to `true`. The extension will be critical.
377    pub fn critical(&mut self) -> &mut AuthorityKeyIdentifier {
378        self.critical = true;
379        self
380    }
381
382    /// Sets the `keyid` flag.
383    pub fn keyid(&mut self, always: bool) -> &mut AuthorityKeyIdentifier {
384        self.keyid = Some(always);
385        self
386    }
387
388    /// Sets the `issuer` flag.
389    pub fn issuer(&mut self, always: bool) -> &mut AuthorityKeyIdentifier {
390        self.issuer = Some(always);
391        self
392    }
393
394    /// Return a `AuthorityKeyIdentifier` extension as an `X509Extension`.
395    pub fn build(&self, ctx: &X509v3Context) -> Result<X509Extension, ErrorStack> {
396        let mut value = String::new();
397        let mut first = true;
398        append(&mut value, &mut first, self.critical, "critical");
399        match self.keyid {
400            Some(true) => append(&mut value, &mut first, true, "keyid:always"),
401            Some(false) => append(&mut value, &mut first, true, "keyid"),
402            None => {}
403        }
404        match self.issuer {
405            Some(true) => append(&mut value, &mut first, true, "issuer:always"),
406            Some(false) => append(&mut value, &mut first, true, "issuer"),
407            None => {}
408        }
409        X509Extension::new_nid(None, Some(ctx), Nid::AUTHORITY_KEY_IDENTIFIER, &value)
410    }
411}
412
413enum RustGeneralName {
414    Dns(String),
415    Email(String),
416    Uri(String),
417    Ip(String),
418    Rid(String),
419}
420
421/// An extension that allows additional identities to be bound to the subject
422/// of the certificate.
423pub struct SubjectAlternativeName {
424    critical: bool,
425    items: Vec<RustGeneralName>,
426}
427
428impl Default for SubjectAlternativeName {
429    fn default() -> SubjectAlternativeName {
430        SubjectAlternativeName::new()
431    }
432}
433
434impl SubjectAlternativeName {
435    /// Construct a new `SubjectAlternativeName` extension.
436    pub fn new() -> SubjectAlternativeName {
437        SubjectAlternativeName {
438            critical: false,
439            items: vec![],
440        }
441    }
442
443    /// Sets the `critical` flag to `true`. The extension will be critical.
444    pub fn critical(&mut self) -> &mut SubjectAlternativeName {
445        self.critical = true;
446        self
447    }
448
449    /// Sets the `email` flag.
450    pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName {
451        self.items.push(RustGeneralName::Email(email.to_string()));
452        self
453    }
454
455    /// Sets the `uri` flag.
456    pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName {
457        self.items.push(RustGeneralName::Uri(uri.to_string()));
458        self
459    }
460
461    /// Sets the `dns` flag.
462    pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName {
463        self.items.push(RustGeneralName::Dns(dns.to_string()));
464        self
465    }
466
467    /// Sets the `rid` flag.
468    pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName {
469        self.items.push(RustGeneralName::Rid(rid.to_string()));
470        self
471    }
472
473    /// Sets the `ip` flag.
474    pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName {
475        self.items.push(RustGeneralName::Ip(ip.to_string()));
476        self
477    }
478
479    /// Sets the `dirName` flag.
480    ///
481    /// Not currently actually supported, always panics.
482    #[deprecated = "dir_name is deprecated and always panics. Please file a bug if you have a use case for this."]
483    pub fn dir_name(&mut self, _dir_name: &str) -> &mut SubjectAlternativeName {
484        unimplemented!(
485            "This has not yet been adapted for the new internals. File a bug if you need this."
486        );
487    }
488
489    /// Sets the `otherName` flag.
490    ///
491    /// Not currently actually supported, always panics.
492    #[deprecated = "other_name is deprecated and always panics. Please file a bug if you have a use case for this."]
493    pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName {
494        unimplemented!(
495            "This has not yet been adapted for the new internals. File a bug if you need this."
496        );
497    }
498
499    /// Return a `SubjectAlternativeName` extension as an `X509Extension`.
500    pub fn build(&self, _ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
501        let mut stack = Stack::new()?;
502        for item in &self.items {
503            let gn = match item {
504                RustGeneralName::Dns(s) => GeneralName::new_dns(s.as_bytes())?,
505                RustGeneralName::Email(s) => GeneralName::new_email(s.as_bytes())?,
506                RustGeneralName::Uri(s) => GeneralName::new_uri(s.as_bytes())?,
507                RustGeneralName::Ip(s) => {
508                    GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)?
509                }
510                RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?,
511            };
512            stack.push(gn)?;
513        }
514
515        unsafe {
516            X509Extension::new_internal(Nid::SUBJECT_ALT_NAME, self.critical, stack.as_ptr().cast())
517        }
518    }
519}
520
521fn append(value: &mut String, first: &mut bool, should: bool, element: &str) {
522    if !should {
523        return;
524    }
525
526    if !*first {
527        value.push(',');
528    }
529    *first = false;
530    value.push_str(element);
531}