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 = String::new();
360 let mut first: bool = true;
361 append(&mut value, &mut first, self.critical, element:"critical");
362 append(&mut value, &mut first, should:true, element:"hash");
363 X509Extension::new_nid(conf:None, context:Some(ctx), name: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(ch:',');
559 }
560 *first = false;
561 value.push_str(string:element);
562}
563