variant_ssl/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, X509Name, 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    DirName(X509Name),
439}
440
441/// An extension that allows additional identities to be bound to the subject
442/// of the certificate.
443pub struct SubjectAlternativeName {
444    critical: bool,
445    items: Vec<RustGeneralName>,
446}
447
448impl Default for SubjectAlternativeName {
449    fn default() -> SubjectAlternativeName {
450        SubjectAlternativeName::new()
451    }
452}
453
454impl SubjectAlternativeName {
455    /// Construct a new `SubjectAlternativeName` extension.
456    pub fn new() -> SubjectAlternativeName {
457        SubjectAlternativeName {
458            critical: false,
459            items: vec![],
460        }
461    }
462
463    /// Sets the `critical` flag to `true`. The extension will be critical.
464    pub fn critical(&mut self) -> &mut SubjectAlternativeName {
465        self.critical = true;
466        self
467    }
468
469    /// Sets the `email` flag.
470    pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName {
471        self.items.push(RustGeneralName::Email(email.to_string()));
472        self
473    }
474
475    /// Sets the `uri` flag.
476    pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName {
477        self.items.push(RustGeneralName::Uri(uri.to_string()));
478        self
479    }
480
481    /// Sets the `dns` flag.
482    pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName {
483        self.items.push(RustGeneralName::Dns(dns.to_string()));
484        self
485    }
486
487    /// Sets the `rid` flag.
488    pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName {
489        self.items.push(RustGeneralName::Rid(rid.to_string()));
490        self
491    }
492
493    /// Sets the `ip` flag.
494    pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName {
495        self.items.push(RustGeneralName::Ip(ip.to_string()));
496        self
497    }
498
499    /// Sets the `dirName` flag.
500    ///
501    /// Not currently actually supported, always panics. Please use dir_name2
502    #[deprecated = "dir_name is deprecated and always panics. Please use dir_name2."]
503    pub fn dir_name(&mut self, _dir_name: &str) -> &mut SubjectAlternativeName {
504        unimplemented!("This has not yet been adapted for the new internals. Use dir_name2.");
505    }
506
507    /// Sets the `dirName` flag.
508    pub fn dir_name2(&mut self, dir_name: X509Name) -> &mut SubjectAlternativeName {
509        self.items.push(RustGeneralName::DirName(dir_name));
510        self
511    }
512
513    /// Sets the `otherName` flag.
514    ///
515    /// Not currently actually supported, always panics. Please use other_name2
516    #[deprecated = "other_name is deprecated and always panics. Please use other_name2."]
517    pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName {
518        unimplemented!("This has not yet been adapted for the new internals. Use other_name2.");
519    }
520
521    /// Sets the `otherName` flag.
522    ///
523    /// `content` must be a valid der encoded ASN1_TYPE
524    ///
525    /// If you want to add just a ia5string use `other_name_ia5string`
526    pub fn other_name2(&mut self, oid: Asn1Object, content: &[u8]) -> &mut SubjectAlternativeName {
527        self.items
528            .push(RustGeneralName::OtherName(oid, content.into()));
529        self
530    }
531
532    /// Return a `SubjectAlternativeName` extension as an `X509Extension`.
533    pub fn build(&self, _ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
534        let mut stack = Stack::new()?;
535        for item in &self.items {
536            let gn = match item {
537                RustGeneralName::Dns(s) => GeneralName::new_dns(s.as_bytes())?,
538                RustGeneralName::Email(s) => GeneralName::new_email(s.as_bytes())?,
539                RustGeneralName::Uri(s) => GeneralName::new_uri(s.as_bytes())?,
540                RustGeneralName::Ip(s) => {
541                    GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)?
542                }
543                RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?,
544                RustGeneralName::OtherName(oid, content) => {
545                    GeneralName::new_other_name(oid.clone(), content)?
546                }
547                RustGeneralName::DirName(name) => GeneralName::new_dir_name(name.as_ref())?,
548            };
549            stack.push(gn)?;
550        }
551
552        unsafe {
553            X509Extension::new_internal(Nid::SUBJECT_ALT_NAME, self.critical, stack.as_ptr().cast())
554        }
555    }
556}
557
558fn append(value: &mut String, first: &mut bool, should: bool, element: &str) {
559    if !should {
560        return;
561    }
562
563    if !*first {
564        value.push(',');
565    }
566    *first = false;
567    value.push_str(element);
568}