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::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} 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(','); 559 } 560 *first = false; 561 value.push_str(element); 562} 563