1use 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
26pub 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    #[must_use]
42    pub fn new() -> BasicConstraints {
43        BasicConstraints {
44            critical: false,
45            ca: false,
46            pathlen: None,
47        }
48    }
49
50    pub fn critical(&mut self) -> &mut BasicConstraints {
52        self.critical = true;
53        self
54    }
55
56    pub fn ca(&mut self) -> &mut BasicConstraints {
58        self.ca = true;
59        self
60    }
61
62    pub fn pathlen(&mut self, pathlen: u32) -> &mut BasicConstraints {
65        self.pathlen = Some(pathlen);
66        self
67    }
68
69    pub fn build(&self) -> Result<X509Extension, ErrorStack> {
71        let mut value = String::new();
72        if self.critical {
73            value.push_str("critical,");
74        }
75        value.push_str("CA:");
76        if self.ca {
77            value.push_str("TRUE");
78        } else {
79            value.push_str("FALSE");
80        }
81        if let Some(pathlen) = self.pathlen {
82            write!(value, ",pathlen:{pathlen}").unwrap();
83        }
84        X509Extension::new_nid(None, None, Nid::BASIC_CONSTRAINTS, &value)
85    }
86}
87
88pub struct KeyUsage {
90    critical: bool,
91    digital_signature: bool,
92    non_repudiation: bool,
93    key_encipherment: bool,
94    data_encipherment: bool,
95    key_agreement: bool,
96    key_cert_sign: bool,
97    crl_sign: bool,
98    encipher_only: bool,
99    decipher_only: bool,
100}
101
102impl Default for KeyUsage {
103    fn default() -> KeyUsage {
104        KeyUsage::new()
105    }
106}
107
108impl KeyUsage {
109    #[must_use]
111    pub fn new() -> KeyUsage {
112        KeyUsage {
113            critical: false,
114            digital_signature: false,
115            non_repudiation: false,
116            key_encipherment: false,
117            data_encipherment: false,
118            key_agreement: false,
119            key_cert_sign: false,
120            crl_sign: false,
121            encipher_only: false,
122            decipher_only: false,
123        }
124    }
125
126    pub fn critical(&mut self) -> &mut KeyUsage {
128        self.critical = true;
129        self
130    }
131
132    pub fn digital_signature(&mut self) -> &mut KeyUsage {
134        self.digital_signature = true;
135        self
136    }
137
138    pub fn non_repudiation(&mut self) -> &mut KeyUsage {
140        self.non_repudiation = true;
141        self
142    }
143
144    pub fn key_encipherment(&mut self) -> &mut KeyUsage {
146        self.key_encipherment = true;
147        self
148    }
149
150    pub fn data_encipherment(&mut self) -> &mut KeyUsage {
152        self.data_encipherment = true;
153        self
154    }
155
156    pub fn key_agreement(&mut self) -> &mut KeyUsage {
158        self.key_agreement = true;
159        self
160    }
161
162    pub fn key_cert_sign(&mut self) -> &mut KeyUsage {
164        self.key_cert_sign = true;
165        self
166    }
167
168    pub fn crl_sign(&mut self) -> &mut KeyUsage {
170        self.crl_sign = true;
171        self
172    }
173
174    pub fn encipher_only(&mut self) -> &mut KeyUsage {
176        self.encipher_only = true;
177        self
178    }
179
180    pub fn decipher_only(&mut self) -> &mut KeyUsage {
182        self.decipher_only = true;
183        self
184    }
185
186    pub fn build(&self) -> Result<X509Extension, ErrorStack> {
188        let mut value = String::new();
189        let mut first = true;
190        append(&mut value, &mut first, self.critical, "critical");
191        append(
192            &mut value,
193            &mut first,
194            self.digital_signature,
195            "digitalSignature",
196        );
197        append(
198            &mut value,
199            &mut first,
200            self.non_repudiation,
201            "nonRepudiation",
202        );
203        append(
204            &mut value,
205            &mut first,
206            self.key_encipherment,
207            "keyEncipherment",
208        );
209        append(
210            &mut value,
211            &mut first,
212            self.data_encipherment,
213            "dataEncipherment",
214        );
215        append(&mut value, &mut first, self.key_agreement, "keyAgreement");
216        append(&mut value, &mut first, self.key_cert_sign, "keyCertSign");
217        append(&mut value, &mut first, self.crl_sign, "cRLSign");
218        append(&mut value, &mut first, self.encipher_only, "encipherOnly");
219        append(&mut value, &mut first, self.decipher_only, "decipherOnly");
220        X509Extension::new_nid(None, None, Nid::KEY_USAGE, &value)
221    }
222}
223
224pub struct ExtendedKeyUsage {
227    critical: bool,
228    items: Vec<String>,
229}
230
231impl Default for ExtendedKeyUsage {
232    fn default() -> ExtendedKeyUsage {
233        ExtendedKeyUsage::new()
234    }
235}
236
237impl ExtendedKeyUsage {
238    #[must_use]
240    pub fn new() -> ExtendedKeyUsage {
241        ExtendedKeyUsage {
242            critical: false,
243            items: vec![],
244        }
245    }
246
247    pub fn critical(&mut self) -> &mut ExtendedKeyUsage {
249        self.critical = true;
250        self
251    }
252
253    pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage {
255        self.other("serverAuth")
256    }
257
258    pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage {
260        self.other("clientAuth")
261    }
262
263    pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage {
265        self.other("codeSigning")
266    }
267
268    pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage {
270        self.other("timeStamping")
271    }
272
273    pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage {
275        self.other("msCodeInd")
276    }
277
278    pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage {
280        self.other("msCodeCom")
281    }
282
283    pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage {
285        self.other("msCTLSign")
286    }
287
288    pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage {
290        self.other("msSGC")
291    }
292
293    pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage {
295        self.other("msEFS")
296    }
297
298    pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage {
300        self.other("nsSGC")
301    }
302
303    pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage {
305        self.items.push(other.to_string());
306        self
307    }
308
309    pub fn build(&self) -> Result<X509Extension, ErrorStack> {
311        let mut stack = Stack::new()?;
312        for item in &self.items {
313            stack.push(Asn1Object::from_str(item)?)?;
314        }
315        unsafe {
316            X509Extension::new_internal(Nid::EXT_KEY_USAGE, self.critical, stack.as_ptr().cast())
317        }
318    }
319}
320
321pub struct SubjectKeyIdentifier {
324    critical: bool,
325}
326
327impl Default for SubjectKeyIdentifier {
328    fn default() -> SubjectKeyIdentifier {
329        SubjectKeyIdentifier::new()
330    }
331}
332
333impl SubjectKeyIdentifier {
334    #[must_use]
336    pub fn new() -> SubjectKeyIdentifier {
337        SubjectKeyIdentifier { critical: false }
338    }
339
340    pub fn critical(&mut self) -> &mut SubjectKeyIdentifier {
342        self.critical = true;
343        self
344    }
345
346    pub fn build(&self, ctx: &X509v3Context) -> Result<X509Extension, ErrorStack> {
348        let mut value = String::new();
349        let mut first = true;
350        append(&mut value, &mut first, self.critical, "critical");
351        append(&mut value, &mut first, true, "hash");
352        X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_KEY_IDENTIFIER, &value)
353    }
354}
355
356pub struct AuthorityKeyIdentifier {
359    critical: bool,
360    keyid: Option<bool>,
361    issuer: Option<bool>,
362}
363
364impl Default for AuthorityKeyIdentifier {
365    fn default() -> AuthorityKeyIdentifier {
366        AuthorityKeyIdentifier::new()
367    }
368}
369
370impl AuthorityKeyIdentifier {
371    #[must_use]
373    pub fn new() -> AuthorityKeyIdentifier {
374        AuthorityKeyIdentifier {
375            critical: false,
376            keyid: None,
377            issuer: None,
378        }
379    }
380
381    pub fn critical(&mut self) -> &mut AuthorityKeyIdentifier {
383        self.critical = true;
384        self
385    }
386
387    pub fn keyid(&mut self, always: bool) -> &mut AuthorityKeyIdentifier {
389        self.keyid = Some(always);
390        self
391    }
392
393    pub fn issuer(&mut self, always: bool) -> &mut AuthorityKeyIdentifier {
395        self.issuer = Some(always);
396        self
397    }
398
399    pub fn build(&self, ctx: &X509v3Context) -> Result<X509Extension, ErrorStack> {
401        let mut value = String::new();
402        let mut first = true;
403        append(&mut value, &mut first, self.critical, "critical");
404        match self.keyid {
405            Some(true) => append(&mut value, &mut first, true, "keyid:always"),
406            Some(false) => append(&mut value, &mut first, true, "keyid"),
407            None => {}
408        }
409        match self.issuer {
410            Some(true) => append(&mut value, &mut first, true, "issuer:always"),
411            Some(false) => append(&mut value, &mut first, true, "issuer"),
412            None => {}
413        }
414        X509Extension::new_nid(None, Some(ctx), Nid::AUTHORITY_KEY_IDENTIFIER, &value)
415    }
416}
417
418enum RustGeneralName {
419    Dns(String),
420    Email(String),
421    Uri(String),
422    Ip(String),
423    Rid(String),
424}
425
426pub struct SubjectAlternativeName {
429    critical: bool,
430    items: Vec<RustGeneralName>,
431}
432
433impl Default for SubjectAlternativeName {
434    fn default() -> SubjectAlternativeName {
435        SubjectAlternativeName::new()
436    }
437}
438
439impl SubjectAlternativeName {
440    #[must_use]
442    pub fn new() -> SubjectAlternativeName {
443        SubjectAlternativeName {
444            critical: false,
445            items: vec![],
446        }
447    }
448
449    pub fn critical(&mut self) -> &mut SubjectAlternativeName {
451        self.critical = true;
452        self
453    }
454
455    pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName {
457        self.items.push(RustGeneralName::Email(email.to_string()));
458        self
459    }
460
461    pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName {
463        self.items.push(RustGeneralName::Uri(uri.to_string()));
464        self
465    }
466
467    pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName {
469        self.items.push(RustGeneralName::Dns(dns.to_string()));
470        self
471    }
472
473    pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName {
475        self.items.push(RustGeneralName::Rid(rid.to_string()));
476        self
477    }
478
479    pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName {
481        self.items.push(RustGeneralName::Ip(ip.to_string()));
482        self
483    }
484
485    #[deprecated = "dir_name is deprecated and always panics. Please file a bug if you have a use case for this."]
489    pub fn dir_name(&mut self, _dir_name: &str) -> &mut SubjectAlternativeName {
490        unimplemented!(
491            "This has not yet been adapted for the new internals. File a bug if you need this."
492        );
493    }
494
495    #[deprecated = "other_name is deprecated and always panics. Please file a bug if you have a use case for this."]
499    pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName {
500        unimplemented!(
501            "This has not yet been adapted for the new internals. File a bug if you need this."
502        );
503    }
504
505    pub fn build(&self, _ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
507        let mut stack = Stack::new()?;
508        for item in &self.items {
509            let gn = match item {
510                RustGeneralName::Dns(s) => GeneralName::new_dns(s.as_bytes())?,
511                RustGeneralName::Email(s) => GeneralName::new_email(s.as_bytes())?,
512                RustGeneralName::Uri(s) => GeneralName::new_uri(s.as_bytes())?,
513                RustGeneralName::Ip(s) => {
514                    GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)?
515                }
516                RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?,
517            };
518            stack.push(gn)?;
519        }
520
521        unsafe {
522            X509Extension::new_internal(Nid::SUBJECT_ALT_NAME, self.critical, stack.as_ptr().cast())
523        }
524    }
525}
526
527fn append(value: &mut String, first: &mut bool, should: bool, element: &str) {
528    if !should {
529        return;
530    }
531
532    if !*first {
533        value.push(',');
534    }
535    *first = false;
536    value.push_str(element);
537}