1use std::fmt::Write;
20
21use crate::asn1::{Asn1Integer, Asn1Object};
22use crate::bn::BigNum;
23use crate::cvt_p;
24use crate::error::ErrorStack;
25use crate::nid::Nid;
26use crate::x509::{GeneralName, Stack, X509Extension, X509Name, X509v3Context};
27use foreign_types::ForeignType;
28
29pub struct BasicConstraints {
31 critical: bool,
32 ca: bool,
33 pathlen: Option<u32>,
34}
35
36impl Default for BasicConstraints {
37 fn default() -> BasicConstraints {
38 BasicConstraints::new()
39 }
40}
41
42impl BasicConstraints {
43 pub fn new() -> BasicConstraints {
45 BasicConstraints {
46 critical: false,
47 ca: false,
48 pathlen: None,
49 }
50 }
51
52 pub fn critical(&mut self) -> &mut BasicConstraints {
54 self.critical = true;
55 self
56 }
57
58 pub fn ca(&mut self) -> &mut BasicConstraints {
60 self.ca = true;
61 self
62 }
63
64 pub fn pathlen(&mut self, pathlen: u32) -> &mut BasicConstraints {
67 self.pathlen = Some(pathlen);
68 self
69 }
70
71 #[allow(deprecated)]
75 pub fn build(&self) -> Result<X509Extension, ErrorStack> {
76 let mut value = String::new();
77 if self.critical {
78 value.push_str("critical,");
79 }
80 value.push_str("CA:");
81 if self.ca {
82 value.push_str("TRUE");
83 } else {
84 value.push_str("FALSE");
85 }
86 if let Some(pathlen) = self.pathlen {
87 write!(value, ",pathlen:{}", pathlen).unwrap();
88 }
89 X509Extension::new_nid(None, None, Nid::BASIC_CONSTRAINTS, &value)
90 }
91}
92
93pub struct KeyUsage {
95 critical: bool,
96 digital_signature: bool,
97 non_repudiation: bool,
98 key_encipherment: bool,
99 data_encipherment: bool,
100 key_agreement: bool,
101 key_cert_sign: bool,
102 crl_sign: bool,
103 encipher_only: bool,
104 decipher_only: bool,
105}
106
107impl Default for KeyUsage {
108 fn default() -> KeyUsage {
109 KeyUsage::new()
110 }
111}
112
113impl KeyUsage {
114 pub fn new() -> KeyUsage {
116 KeyUsage {
117 critical: false,
118 digital_signature: false,
119 non_repudiation: false,
120 key_encipherment: false,
121 data_encipherment: false,
122 key_agreement: false,
123 key_cert_sign: false,
124 crl_sign: false,
125 encipher_only: false,
126 decipher_only: false,
127 }
128 }
129
130 pub fn critical(&mut self) -> &mut KeyUsage {
132 self.critical = true;
133 self
134 }
135
136 pub fn digital_signature(&mut self) -> &mut KeyUsage {
138 self.digital_signature = true;
139 self
140 }
141
142 pub fn non_repudiation(&mut self) -> &mut KeyUsage {
144 self.non_repudiation = true;
145 self
146 }
147
148 pub fn key_encipherment(&mut self) -> &mut KeyUsage {
150 self.key_encipherment = true;
151 self
152 }
153
154 pub fn data_encipherment(&mut self) -> &mut KeyUsage {
156 self.data_encipherment = true;
157 self
158 }
159
160 pub fn key_agreement(&mut self) -> &mut KeyUsage {
162 self.key_agreement = true;
163 self
164 }
165
166 pub fn key_cert_sign(&mut self) -> &mut KeyUsage {
168 self.key_cert_sign = true;
169 self
170 }
171
172 pub fn crl_sign(&mut self) -> &mut KeyUsage {
174 self.crl_sign = true;
175 self
176 }
177
178 pub fn encipher_only(&mut self) -> &mut KeyUsage {
180 self.encipher_only = true;
181 self
182 }
183
184 pub fn decipher_only(&mut self) -> &mut KeyUsage {
186 self.decipher_only = true;
187 self
188 }
189
190 #[allow(deprecated)]
194 pub fn build(&self) -> Result<X509Extension, ErrorStack> {
195 let mut value = String::new();
196 let mut first = true;
197 append(&mut value, &mut first, self.critical, "critical");
198 append(
199 &mut value,
200 &mut first,
201 self.digital_signature,
202 "digitalSignature",
203 );
204 append(
205 &mut value,
206 &mut first,
207 self.non_repudiation,
208 "nonRepudiation",
209 );
210 append(
211 &mut value,
212 &mut first,
213 self.key_encipherment,
214 "keyEncipherment",
215 );
216 append(
217 &mut value,
218 &mut first,
219 self.data_encipherment,
220 "dataEncipherment",
221 );
222 append(&mut value, &mut first, self.key_agreement, "keyAgreement");
223 append(&mut value, &mut first, self.key_cert_sign, "keyCertSign");
224 append(&mut value, &mut first, self.crl_sign, "cRLSign");
225 append(&mut value, &mut first, self.encipher_only, "encipherOnly");
226 append(&mut value, &mut first, self.decipher_only, "decipherOnly");
227 X509Extension::new_nid(None, None, Nid::KEY_USAGE, &value)
228 }
229}
230
231pub struct ExtendedKeyUsage {
234 critical: bool,
235 items: Vec<String>,
236}
237
238impl Default for ExtendedKeyUsage {
239 fn default() -> ExtendedKeyUsage {
240 ExtendedKeyUsage::new()
241 }
242}
243
244impl ExtendedKeyUsage {
245 pub fn new() -> ExtendedKeyUsage {
247 ExtendedKeyUsage {
248 critical: false,
249 items: vec![],
250 }
251 }
252
253 pub fn critical(&mut self) -> &mut ExtendedKeyUsage {
255 self.critical = true;
256 self
257 }
258
259 pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage {
261 self.other("serverAuth")
262 }
263
264 pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage {
266 self.other("clientAuth")
267 }
268
269 pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage {
271 self.other("codeSigning")
272 }
273
274 pub fn email_protection(&mut self) -> &mut ExtendedKeyUsage {
276 self.other("emailProtection")
277 }
278
279 pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage {
281 self.other("timeStamping")
282 }
283
284 pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage {
286 self.other("msCodeInd")
287 }
288
289 pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage {
291 self.other("msCodeCom")
292 }
293
294 pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage {
296 self.other("msCTLSign")
297 }
298
299 pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage {
301 self.other("msSGC")
302 }
303
304 pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage {
306 self.other("msEFS")
307 }
308
309 pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage {
311 self.other("nsSGC")
312 }
313
314 pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage {
316 self.items.push(other.to_string());
317 self
318 }
319
320 pub fn build(&self) -> Result<X509Extension, ErrorStack> {
322 let mut stack = Stack::new()?;
323 for item in &self.items {
324 stack.push(Asn1Object::from_str(item)?)?;
325 }
326 unsafe {
327 X509Extension::new_internal(Nid::EXT_KEY_USAGE, self.critical, stack.as_ptr().cast())
328 }
329 }
330}
331
332pub struct SubjectKeyIdentifier {
335 critical: bool,
336}
337
338impl Default for SubjectKeyIdentifier {
339 fn default() -> SubjectKeyIdentifier {
340 SubjectKeyIdentifier::new()
341 }
342}
343
344impl SubjectKeyIdentifier {
345 pub fn new() -> SubjectKeyIdentifier {
347 SubjectKeyIdentifier { critical: false }
348 }
349
350 pub fn critical(&mut self) -> &mut SubjectKeyIdentifier {
352 self.critical = true;
353 self
354 }
355
356 #[allow(deprecated)]
360 pub fn build(&self, ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
361 let mut value = String::new();
362 let mut first = true;
363 append(&mut value, &mut first, self.critical, "critical");
364 append(&mut value, &mut first, true, "hash");
365 X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_KEY_IDENTIFIER, &value)
366 }
367}
368
369pub struct AuthorityKeyIdentifier {
372 critical: bool,
373 keyid: Option<bool>,
374 issuer: Option<bool>,
375}
376
377impl Default for AuthorityKeyIdentifier {
378 fn default() -> AuthorityKeyIdentifier {
379 AuthorityKeyIdentifier::new()
380 }
381}
382
383impl AuthorityKeyIdentifier {
384 pub fn new() -> AuthorityKeyIdentifier {
386 AuthorityKeyIdentifier {
387 critical: false,
388 keyid: None,
389 issuer: None,
390 }
391 }
392
393 pub fn critical(&mut self) -> &mut AuthorityKeyIdentifier {
395 self.critical = true;
396 self
397 }
398
399 pub fn keyid(&mut self, always: bool) -> &mut AuthorityKeyIdentifier {
401 self.keyid = Some(always);
402 self
403 }
404
405 pub fn issuer(&mut self, always: bool) -> &mut AuthorityKeyIdentifier {
407 self.issuer = Some(always);
408 self
409 }
410
411 #[allow(deprecated)]
415 pub fn build(&self, ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
416 let mut value = String::new();
417 let mut first = true;
418 append(&mut value, &mut first, self.critical, "critical");
419 match self.keyid {
420 Some(true) => append(&mut value, &mut first, true, "keyid:always"),
421 Some(false) => append(&mut value, &mut first, true, "keyid"),
422 None => {}
423 }
424 match self.issuer {
425 Some(true) => append(&mut value, &mut first, true, "issuer:always"),
426 Some(false) => append(&mut value, &mut first, true, "issuer"),
427 None => {}
428 }
429 X509Extension::new_nid(None, Some(ctx), Nid::AUTHORITY_KEY_IDENTIFIER, &value)
430 }
431}
432
433enum RustGeneralName {
434 Dns(String),
435 Email(String),
436 Uri(String),
437 Ip(String),
438 Rid(String),
439 OtherName(Asn1Object, Vec<u8>),
440 DirName(X509Name),
441}
442
443pub struct SubjectAlternativeName {
446 critical: bool,
447 items: Vec<RustGeneralName>,
448}
449
450impl Default for SubjectAlternativeName {
451 fn default() -> SubjectAlternativeName {
452 SubjectAlternativeName::new()
453 }
454}
455
456impl SubjectAlternativeName {
457 pub fn new() -> SubjectAlternativeName {
459 SubjectAlternativeName {
460 critical: false,
461 items: vec![],
462 }
463 }
464
465 pub fn critical(&mut self) -> &mut SubjectAlternativeName {
467 self.critical = true;
468 self
469 }
470
471 pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName {
473 self.items.push(RustGeneralName::Email(email.to_string()));
474 self
475 }
476
477 pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName {
479 self.items.push(RustGeneralName::Uri(uri.to_string()));
480 self
481 }
482
483 pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName {
485 self.items.push(RustGeneralName::Dns(dns.to_string()));
486 self
487 }
488
489 pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName {
491 self.items.push(RustGeneralName::Rid(rid.to_string()));
492 self
493 }
494
495 pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName {
497 self.items.push(RustGeneralName::Ip(ip.to_string()));
498 self
499 }
500
501 #[deprecated = "dir_name is deprecated and always panics. Please use dir_name2."]
505 pub fn dir_name(&mut self, _dir_name: &str) -> &mut SubjectAlternativeName {
506 unimplemented!("This has not yet been adapted for the new internals. Use dir_name2.");
507 }
508
509 pub fn dir_name2(&mut self, dir_name: X509Name) -> &mut SubjectAlternativeName {
511 self.items.push(RustGeneralName::DirName(dir_name));
512 self
513 }
514
515 #[deprecated = "other_name is deprecated and always panics. Please use other_name2."]
519 pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName {
520 unimplemented!("This has not yet been adapted for the new internals. Use other_name2.");
521 }
522
523 pub fn other_name2(&mut self, oid: Asn1Object, content: &[u8]) -> &mut SubjectAlternativeName {
529 self.items
530 .push(RustGeneralName::OtherName(oid, content.into()));
531 self
532 }
533
534 pub fn build(&self, _ctx: &X509v3Context<'_>) -> Result<X509Extension, ErrorStack> {
536 let mut stack = Stack::new()?;
537 for item in &self.items {
538 let gn = match item {
539 RustGeneralName::Dns(s) => GeneralName::new_dns(s.as_bytes())?,
540 RustGeneralName::Email(s) => GeneralName::new_email(s.as_bytes())?,
541 RustGeneralName::Uri(s) => GeneralName::new_uri(s.as_bytes())?,
542 RustGeneralName::Ip(s) => {
543 GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)?
544 }
545 RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?,
546 RustGeneralName::OtherName(oid, content) => {
547 GeneralName::new_other_name(oid.clone(), content)?
548 }
549 RustGeneralName::DirName(name) => GeneralName::new_dir_name(name.as_ref())?,
550 };
551 stack.push(gn)?;
552 }
553
554 unsafe {
555 X509Extension::new_internal(Nid::SUBJECT_ALT_NAME, self.critical, stack.as_ptr().cast())
556 }
557 }
558}
559
560pub struct CrlNumber(Asn1Integer);
562
563impl CrlNumber {
564 pub fn new(number: BigNum) -> Result<Self, ErrorStack> {
566 let mut max = BigNum::new()?;
567 max.lshift(BigNum::from_u32(1)?.as_ref(), 159)?;
568
569 assert!(
570 !number.is_negative() && number < max,
571 "CrlNumber must be an ASN.1 integer greater than or equal to 0 and less than 2^159"
572 );
573
574 Ok(Self(Asn1Integer::from_bn(&number)?))
575 }
576
577 pub fn build(self) -> Result<X509Extension, ErrorStack> {
579 unsafe {
580 ffi::init();
581
582 cvt_p(ffi::X509V3_EXT_i2d(
583 Nid::CRL_NUMBER.as_raw(),
584 0,
585 self.0.as_ptr().cast(),
586 ))
587 .map(X509Extension)
588 }
589 }
590}
591
592fn append(value: &mut String, first: &mut bool, should: bool, element: &str) {
593 if !should {
594 return;
595 }
596
597 if !*first {
598 value.push(',');
599 }
600 *first = false;
601 value.push_str(element);
602}