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