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 pub fn new() -> BasicConstraints {
42 BasicConstraints {
43 critical: false,
44 ca: false,
45 pathlen: None,
46 }
47 }
48
49 pub fn critical(&mut self) -> &mut BasicConstraints {
51 self.critical = true;
52 self
53 }
54
55 pub fn ca(&mut self) -> &mut BasicConstraints {
57 self.ca = true;
58 self
59 }
60
61 pub fn pathlen(&mut self, pathlen: u32) -> &mut BasicConstraints {
64 self.pathlen = Some(pathlen);
65 self
66 }
67
68 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
87pub 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 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 pub fn critical(&mut self) -> &mut KeyUsage {
126 self.critical = true;
127 self
128 }
129
130 pub fn digital_signature(&mut self) -> &mut KeyUsage {
132 self.digital_signature = true;
133 self
134 }
135
136 pub fn non_repudiation(&mut self) -> &mut KeyUsage {
138 self.non_repudiation = true;
139 self
140 }
141
142 pub fn key_encipherment(&mut self) -> &mut KeyUsage {
144 self.key_encipherment = true;
145 self
146 }
147
148 pub fn data_encipherment(&mut self) -> &mut KeyUsage {
150 self.data_encipherment = true;
151 self
152 }
153
154 pub fn key_agreement(&mut self) -> &mut KeyUsage {
156 self.key_agreement = true;
157 self
158 }
159
160 pub fn key_cert_sign(&mut self) -> &mut KeyUsage {
162 self.key_cert_sign = true;
163 self
164 }
165
166 pub fn crl_sign(&mut self) -> &mut KeyUsage {
168 self.crl_sign = true;
169 self
170 }
171
172 pub fn encipher_only(&mut self) -> &mut KeyUsage {
174 self.encipher_only = true;
175 self
176 }
177
178 pub fn decipher_only(&mut self) -> &mut KeyUsage {
180 self.decipher_only = true;
181 self
182 }
183
184 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
222pub 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 pub fn new() -> ExtendedKeyUsage {
238 ExtendedKeyUsage {
239 critical: false,
240 items: vec![],
241 }
242 }
243
244 pub fn critical(&mut self) -> &mut ExtendedKeyUsage {
246 self.critical = true;
247 self
248 }
249
250 pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage {
252 self.other("serverAuth")
253 }
254
255 pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage {
257 self.other("clientAuth")
258 }
259
260 pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage {
262 self.other("codeSigning")
263 }
264
265 pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage {
267 self.other("timeStamping")
268 }
269
270 pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage {
272 self.other("msCodeInd")
273 }
274
275 pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage {
277 self.other("msCodeCom")
278 }
279
280 pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage {
282 self.other("msCTLSign")
283 }
284
285 pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage {
287 self.other("msSGC")
288 }
289
290 pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage {
292 self.other("msEFS")
293 }
294
295 pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage {
297 self.other("nsSGC")
298 }
299
300 pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage {
302 self.items.push(other.to_string());
303 self
304 }
305
306 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
318pub struct SubjectKeyIdentifier {
321 critical: bool,
322}
323
324impl Default for SubjectKeyIdentifier {
325 fn default() -> SubjectKeyIdentifier {
326 SubjectKeyIdentifier::new()
327 }
328}
329
330impl SubjectKeyIdentifier {
331 pub fn new() -> SubjectKeyIdentifier {
333 SubjectKeyIdentifier { critical: false }
334 }
335
336 pub fn critical(&mut self) -> &mut SubjectKeyIdentifier {
338 self.critical = true;
339 self
340 }
341
342 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
352pub 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 pub fn new() -> AuthorityKeyIdentifier {
369 AuthorityKeyIdentifier {
370 critical: false,
371 keyid: None,
372 issuer: None,
373 }
374 }
375
376 pub fn critical(&mut self) -> &mut AuthorityKeyIdentifier {
378 self.critical = true;
379 self
380 }
381
382 pub fn keyid(&mut self, always: bool) -> &mut AuthorityKeyIdentifier {
384 self.keyid = Some(always);
385 self
386 }
387
388 pub fn issuer(&mut self, always: bool) -> &mut AuthorityKeyIdentifier {
390 self.issuer = Some(always);
391 self
392 }
393
394 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
421pub 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 pub fn new() -> SubjectAlternativeName {
437 SubjectAlternativeName {
438 critical: false,
439 items: vec![],
440 }
441 }
442
443 pub fn critical(&mut self) -> &mut SubjectAlternativeName {
445 self.critical = true;
446 self
447 }
448
449 pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName {
451 self.items.push(RustGeneralName::Email(email.to_string()));
452 self
453 }
454
455 pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName {
457 self.items.push(RustGeneralName::Uri(uri.to_string()));
458 self
459 }
460
461 pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName {
463 self.items.push(RustGeneralName::Dns(dns.to_string()));
464 self
465 }
466
467 pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName {
469 self.items.push(RustGeneralName::Rid(rid.to_string()));
470 self
471 }
472
473 pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName {
475 self.items.push(RustGeneralName::Ip(ip.to_string()));
476 self
477 }
478
479 #[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 #[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 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}