1 //! The standard defining the format of public key certificates. 2 //! 3 //! An `X509` certificate binds an identity to a public key, and is either 4 //! signed by a certificate authority (CA) or self-signed. An entity that gets 5 //! a hold of a certificate can both verify your identity (via a CA) and encrypt 6 //! data with the included public key. `X509` certificates are used in many 7 //! Internet protocols, including SSL/TLS, which is the basis for HTTPS, 8 //! the secure protocol for browsing the web. 9 10 use cfg_if::cfg_if; 11 use foreign_types::{ForeignType, ForeignTypeRef}; 12 use libc::{c_int, c_long}; 13 use std::error::Error; 14 use std::ffi::{CStr, CString}; 15 use std::fmt; 16 use std::marker::PhantomData; 17 use std::mem; 18 use std::path::Path; 19 use std::ptr; 20 use std::slice; 21 use std::str; 22 23 use crate::asn1::{ 24 Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef, Asn1Type, 25 }; 26 use crate::bio::MemBioSlice; 27 use crate::conf::ConfRef; 28 use crate::error::ErrorStack; 29 use crate::ex_data::Index; 30 use crate::hash::{DigestBytes, MessageDigest}; 31 use crate::nid::Nid; 32 use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; 33 use crate::ssl::SslRef; 34 use crate::stack::{Stack, StackRef, Stackable}; 35 use crate::string::OpensslString; 36 use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; 37 use crate::{cvt, cvt_n, cvt_p}; 38 39 #[cfg(any(ossl102, libressl261))] 40 pub mod verify; 41 42 pub mod extension; 43 pub mod store; 44 45 #[cfg(test)] 46 mod tests; 47 48 foreign_type_and_impl_send_sync! { 49 type CType = ffi::X509_STORE_CTX; 50 fn drop = ffi::X509_STORE_CTX_free; 51 52 /// An `X509` certificate store context. 53 pub struct X509StoreContext; 54 55 /// Reference to `X509StoreContext`. 56 pub struct X509StoreContextRef; 57 } 58 59 impl X509StoreContext { 60 /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a 61 /// context. ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack>62 pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> { 63 unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) } 64 } 65 66 /// Creates a new `X509StoreContext` instance. 67 /// 68 /// This corresponds to [`X509_STORE_CTX_new`]. 69 /// 70 /// [`X509_STORE_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_new.html new() -> Result<X509StoreContext, ErrorStack>71 pub fn new() -> Result<X509StoreContext, ErrorStack> { 72 unsafe { 73 ffi::init(); 74 cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext) 75 } 76 } 77 } 78 79 impl X509StoreContextRef { 80 /// Returns application data pertaining to an `X509` store context. 81 /// 82 /// This corresponds to [`X509_STORE_CTX_get_ex_data`]. 83 /// 84 /// [`X509_STORE_CTX_get_ex_data`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_get_ex_data.html ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T>85 pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> { 86 unsafe { 87 let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw()); 88 if data.is_null() { 89 None 90 } else { 91 Some(&*(data as *const T)) 92 } 93 } 94 } 95 96 /// Returns the error code of the context. 97 /// 98 /// This corresponds to [`X509_STORE_CTX_get_error`]. 99 /// 100 /// [`X509_STORE_CTX_get_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error.html error(&self) -> X509VerifyResult101 pub fn error(&self) -> X509VerifyResult { 102 unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) } 103 } 104 105 /// Initializes this context with the given certificate, certificates chain and certificate 106 /// store. After initializing the context, the `with_context` closure is called with the prepared 107 /// context. As long as the closure is running, the context stays initialized and can be used 108 /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished. 109 /// 110 /// * `trust` - The certificate store with the trusted certificates. 111 /// * `cert` - The certificate that should be verified. 112 /// * `cert_chain` - The certificates chain. 113 /// * `with_context` - The closure that is called with the initialized context. 114 /// 115 /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to 116 /// [`X509_STORE_CTX_cleanup`] after calling `with_context`. 117 /// 118 /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html 119 /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html init<F, T>( &mut self, trust: &store::X509StoreRef, cert: &X509Ref, cert_chain: &StackRef<X509>, with_context: F, ) -> Result<T, ErrorStack> where F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,120 pub fn init<F, T>( 121 &mut self, 122 trust: &store::X509StoreRef, 123 cert: &X509Ref, 124 cert_chain: &StackRef<X509>, 125 with_context: F, 126 ) -> Result<T, ErrorStack> 127 where 128 F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>, 129 { 130 struct Cleanup<'a>(&'a mut X509StoreContextRef); 131 132 impl<'a> Drop for Cleanup<'a> { 133 fn drop(&mut self) { 134 unsafe { 135 ffi::X509_STORE_CTX_cleanup(self.0.as_ptr()); 136 } 137 } 138 } 139 140 unsafe { 141 cvt(ffi::X509_STORE_CTX_init( 142 self.as_ptr(), 143 trust.as_ptr(), 144 cert.as_ptr(), 145 cert_chain.as_ptr(), 146 ))?; 147 148 let cleanup = Cleanup(self); 149 with_context(cleanup.0) 150 } 151 } 152 153 /// Verifies the stored certificate. 154 /// 155 /// Returns `true` if verification succeeds. The `error` method will return the specific 156 /// validation error if the certificate was not valid. 157 /// 158 /// This will only work inside of a call to `init`. 159 /// 160 /// This corresponds to [`X509_verify_cert`]. 161 /// 162 /// [`X509_verify_cert`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_verify_cert.html verify_cert(&mut self) -> Result<bool, ErrorStack>163 pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> { 164 unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) } 165 } 166 167 /// Set the error code of the context. 168 /// 169 /// This corresponds to [`X509_STORE_CTX_set_error`]. 170 /// 171 /// [`X509_STORE_CTX_set_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_set_error.html set_error(&mut self, result: X509VerifyResult)172 pub fn set_error(&mut self, result: X509VerifyResult) { 173 unsafe { 174 ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw()); 175 } 176 } 177 178 /// Returns a reference to the certificate which caused the error or None if 179 /// no certificate is relevant to the error. 180 /// 181 /// This corresponds to [`X509_STORE_CTX_get_current_cert`]. 182 /// 183 /// [`X509_STORE_CTX_get_current_cert`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_current_cert.html current_cert(&self) -> Option<&X509Ref>184 pub fn current_cert(&self) -> Option<&X509Ref> { 185 unsafe { 186 let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr()); 187 X509Ref::from_const_ptr_opt(ptr) 188 } 189 } 190 191 /// Returns a non-negative integer representing the depth in the certificate 192 /// chain where the error occurred. If it is zero it occurred in the end 193 /// entity certificate, one if it is the certificate which signed the end 194 /// entity certificate and so on. 195 /// 196 /// This corresponds to [`X509_STORE_CTX_get_error_depth`]. 197 /// 198 /// [`X509_STORE_CTX_get_error_depth`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error_depth.html error_depth(&self) -> u32199 pub fn error_depth(&self) -> u32 { 200 unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 } 201 } 202 203 /// Returns a reference to a complete valid `X509` certificate chain. 204 /// 205 /// This corresponds to [`X509_STORE_CTX_get0_chain`]. 206 /// 207 /// [`X509_STORE_CTX_get0_chain`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get0_chain.html chain(&self) -> Option<&StackRef<X509>>208 pub fn chain(&self) -> Option<&StackRef<X509>> { 209 unsafe { 210 let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); 211 212 if chain.is_null() { 213 None 214 } else { 215 Some(StackRef::from_ptr(chain)) 216 } 217 } 218 } 219 } 220 221 /// A builder used to construct an `X509`. 222 pub struct X509Builder(X509); 223 224 impl X509Builder { 225 /// Creates a new builder. new() -> Result<X509Builder, ErrorStack>226 pub fn new() -> Result<X509Builder, ErrorStack> { 227 unsafe { 228 ffi::init(); 229 cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p))) 230 } 231 } 232 233 /// Sets the notAfter constraint on the certificate. set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack>234 pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { 235 unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } 236 } 237 238 /// Sets the notBefore constraint on the certificate. set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack>239 pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { 240 unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } 241 } 242 243 /// Sets the version of the certificate. 244 /// 245 /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of 246 /// the X.509 standard should pass `2` to this method. set_version(&mut self, version: i32) -> Result<(), ErrorStack>247 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { 248 unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } 249 } 250 251 /// Sets the serial number of the certificate. set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack>252 pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> { 253 unsafe { 254 cvt(ffi::X509_set_serialNumber( 255 self.0.as_ptr(), 256 serial_number.as_ptr(), 257 )) 258 .map(|_| ()) 259 } 260 } 261 262 /// Sets the issuer name of the certificate. set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack>263 pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> { 264 unsafe { 265 cvt(ffi::X509_set_issuer_name( 266 self.0.as_ptr(), 267 issuer_name.as_ptr(), 268 )) 269 .map(|_| ()) 270 } 271 } 272 273 /// Sets the subject name of the certificate. 274 /// 275 /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools. 276 /// The `CN` field is used for the common name, such as a DNS name. 277 /// 278 /// ``` 279 /// use openssl::x509::{X509, X509NameBuilder}; 280 /// 281 /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap(); 282 /// x509_name.append_entry_by_text("C", "US").unwrap(); 283 /// x509_name.append_entry_by_text("ST", "CA").unwrap(); 284 /// x509_name.append_entry_by_text("O", "Some organization").unwrap(); 285 /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap(); 286 /// let x509_name = x509_name.build(); 287 /// 288 /// let mut x509 = openssl::x509::X509::builder().unwrap(); 289 /// x509.set_subject_name(&x509_name).unwrap(); 290 /// ``` set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>291 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { 292 unsafe { 293 cvt(ffi::X509_set_subject_name( 294 self.0.as_ptr(), 295 subject_name.as_ptr(), 296 )) 297 .map(|_| ()) 298 } 299 } 300 301 /// Sets the public key associated with the certificate. set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,302 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> 303 where 304 T: HasPublic, 305 { 306 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } 307 } 308 309 /// Returns a context object which is needed to create certain X509 extension values. 310 /// 311 /// Set `issuer` to `None` if the certificate will be self-signed. x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, conf: Option<&'a ConfRef>, ) -> X509v3Context<'a>312 pub fn x509v3_context<'a>( 313 &'a self, 314 issuer: Option<&'a X509Ref>, 315 conf: Option<&'a ConfRef>, 316 ) -> X509v3Context<'a> { 317 unsafe { 318 let mut ctx = mem::zeroed(); 319 320 let issuer = match issuer { 321 Some(issuer) => issuer.as_ptr(), 322 None => self.0.as_ptr(), 323 }; 324 let subject = self.0.as_ptr(); 325 ffi::X509V3_set_ctx( 326 &mut ctx, 327 issuer, 328 subject, 329 ptr::null_mut(), 330 ptr::null_mut(), 331 0, 332 ); 333 334 // nodb case taken care of since we zeroed ctx above 335 if let Some(conf) = conf { 336 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); 337 } 338 339 X509v3Context(ctx, PhantomData) 340 } 341 } 342 343 /// Adds an X509 extension value to the certificate. 344 /// 345 /// This works just as `append_extension` except it takes ownership of the `X509Extension`. append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack>346 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> { 347 self.append_extension2(&extension) 348 } 349 350 /// Adds an X509 extension value to the certificate. 351 /// 352 /// This corresponds to [`X509_add_ext`]. 353 /// 354 /// [`X509_add_ext`]: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext.html append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack>355 pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> { 356 unsafe { 357 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; 358 Ok(()) 359 } 360 } 361 362 /// Signs the certificate with a private key. sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,363 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> 364 where 365 T: HasPrivate, 366 { 367 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) } 368 } 369 370 /// Consumes the builder, returning the certificate. build(self) -> X509371 pub fn build(self) -> X509 { 372 self.0 373 } 374 } 375 376 foreign_type_and_impl_send_sync! { 377 type CType = ffi::X509; 378 fn drop = ffi::X509_free; 379 380 /// An `X509` public key certificate. 381 pub struct X509; 382 /// Reference to `X509`. 383 pub struct X509Ref; 384 } 385 386 impl X509Ref { 387 /// Returns this certificate's subject name. 388 /// 389 /// This corresponds to [`X509_get_subject_name`]. 390 /// 391 /// [`X509_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html subject_name(&self) -> &X509NameRef392 pub fn subject_name(&self) -> &X509NameRef { 393 unsafe { 394 let name = ffi::X509_get_subject_name(self.as_ptr()); 395 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") 396 } 397 } 398 399 /// Returns the hash of the certificates subject 400 /// 401 /// This corresponds to `X509_subject_name_hash`. subject_name_hash(&self) -> u32402 pub fn subject_name_hash(&self) -> u32 { 403 unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } 404 } 405 406 /// Returns this certificate's issuer name. 407 /// 408 /// This corresponds to [`X509_get_issuer_name`]. 409 /// 410 /// [`X509_get_issuer_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html issuer_name(&self) -> &X509NameRef411 pub fn issuer_name(&self) -> &X509NameRef { 412 unsafe { 413 let name = ffi::X509_get_issuer_name(self.as_ptr()); 414 X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null") 415 } 416 } 417 418 /// Returns this certificate's subject alternative name entries, if they exist. 419 /// 420 /// This corresponds to [`X509_get_ext_d2i`] called with `NID_subject_alt_name`. 421 /// 422 /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html subject_alt_names(&self) -> Option<Stack<GeneralName>>423 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> { 424 unsafe { 425 let stack = ffi::X509_get_ext_d2i( 426 self.as_ptr(), 427 ffi::NID_subject_alt_name, 428 ptr::null_mut(), 429 ptr::null_mut(), 430 ); 431 Stack::from_ptr_opt(stack as *mut _) 432 } 433 } 434 435 /// Returns this certificate's issuer alternative name entries, if they exist. 436 /// 437 /// This corresponds to [`X509_get_ext_d2i`] called with `NID_issuer_alt_name`. 438 /// 439 /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html issuer_alt_names(&self) -> Option<Stack<GeneralName>>440 pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> { 441 unsafe { 442 let stack = ffi::X509_get_ext_d2i( 443 self.as_ptr(), 444 ffi::NID_issuer_alt_name, 445 ptr::null_mut(), 446 ptr::null_mut(), 447 ); 448 Stack::from_ptr_opt(stack as *mut _) 449 } 450 } 451 452 /// Returns this certificate's [`authority information access`] entries, if they exist. 453 /// 454 /// This corresponds to [`X509_get_ext_d2i`] called with `NID_info_access`. 455 /// 456 /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html 457 /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1 authority_info(&self) -> Option<Stack<AccessDescription>>458 pub fn authority_info(&self) -> Option<Stack<AccessDescription>> { 459 unsafe { 460 let stack = ffi::X509_get_ext_d2i( 461 self.as_ptr(), 462 ffi::NID_info_access, 463 ptr::null_mut(), 464 ptr::null_mut(), 465 ); 466 Stack::from_ptr_opt(stack as *mut _) 467 } 468 } 469 public_key(&self) -> Result<PKey<Public>, ErrorStack>470 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> { 471 unsafe { 472 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?; 473 Ok(PKey::from_ptr(pkey)) 474 } 475 } 476 477 /// Returns a digest of the DER representation of the certificate. 478 /// 479 /// This corresponds to [`X509_digest`]. 480 /// 481 /// [`X509_digest`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_digest.html digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack>482 pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> { 483 unsafe { 484 let mut digest = DigestBytes { 485 buf: [0; ffi::EVP_MAX_MD_SIZE as usize], 486 len: ffi::EVP_MAX_MD_SIZE as usize, 487 }; 488 let mut len = ffi::EVP_MAX_MD_SIZE; 489 cvt(ffi::X509_digest( 490 self.as_ptr(), 491 hash_type.as_ptr(), 492 digest.buf.as_mut_ptr() as *mut _, 493 &mut len, 494 ))?; 495 digest.len = len as usize; 496 497 Ok(digest) 498 } 499 } 500 501 #[deprecated(since = "0.10.9", note = "renamed to digest")] fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack>502 pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> { 503 self.digest(hash_type).map(|b| b.to_vec()) 504 } 505 506 /// Returns the certificate's Not After validity period. not_after(&self) -> &Asn1TimeRef507 pub fn not_after(&self) -> &Asn1TimeRef { 508 unsafe { 509 let date = X509_getm_notAfter(self.as_ptr()); 510 Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null") 511 } 512 } 513 514 /// Returns the certificate's Not Before validity period. not_before(&self) -> &Asn1TimeRef515 pub fn not_before(&self) -> &Asn1TimeRef { 516 unsafe { 517 let date = X509_getm_notBefore(self.as_ptr()); 518 Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null") 519 } 520 } 521 522 /// Returns the certificate's signature signature(&self) -> &Asn1BitStringRef523 pub fn signature(&self) -> &Asn1BitStringRef { 524 unsafe { 525 let mut signature = ptr::null(); 526 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); 527 Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null") 528 } 529 } 530 531 /// Returns the certificate's signature algorithm. signature_algorithm(&self) -> &X509AlgorithmRef532 pub fn signature_algorithm(&self) -> &X509AlgorithmRef { 533 unsafe { 534 let mut algor = ptr::null(); 535 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); 536 X509AlgorithmRef::from_const_ptr_opt(algor) 537 .expect("signature algorithm must not be null") 538 } 539 } 540 541 /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information 542 /// Access field. ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack>543 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> { 544 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) } 545 } 546 547 /// Checks that this certificate issued `subject`. issued(&self, subject: &X509Ref) -> X509VerifyResult548 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult { 549 unsafe { 550 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr()); 551 X509VerifyResult::from_raw(r) 552 } 553 } 554 555 /// Returns certificate version. If this certificate has no explicit version set, it defaults to 556 /// version 1. 557 /// 558 /// Note that `0` return value stands for version 1, `1` for version 2 and so on. 559 /// 560 /// This corresponds to [`X509_get_version`]. 561 /// 562 /// [`X509_get_version`]: https://www.openssl.org/docs/man1.1.1/man3/X509_get_version.html 563 #[cfg(ossl110)] version(&self) -> i32564 pub fn version(&self) -> i32 { 565 // Covered with `x509_ref_version()`, `x509_ref_version_no_version_set()` tests 566 unsafe { ffi::X509_get_version(self.as_ptr()) as i32 } 567 } 568 569 /// Check if the certificate is signed using the given public key. 570 /// 571 /// Only the signature is checked: no other checks (such as certificate chain validity) 572 /// are performed. 573 /// 574 /// Returns `true` if verification succeeds. 575 /// 576 /// This corresponds to [`X509_verify"]. 577 /// 578 /// [`X509_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify.html verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,579 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 580 where 581 T: HasPublic, 582 { 583 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 584 } 585 586 /// Returns this certificate's serial number. 587 /// 588 /// This corresponds to [`X509_get_serialNumber`]. 589 /// 590 /// [`X509_get_serialNumber`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_serialNumber.html serial_number(&self) -> &Asn1IntegerRef591 pub fn serial_number(&self) -> &Asn1IntegerRef { 592 unsafe { 593 let r = ffi::X509_get_serialNumber(self.as_ptr()); 594 Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null") 595 } 596 } 597 598 to_pem! { 599 /// Serializes the certificate into a PEM-encoded X509 structure. 600 /// 601 /// The output will have a header of `-----BEGIN CERTIFICATE-----`. 602 /// 603 /// This corresponds to [`PEM_write_bio_X509`]. 604 /// 605 /// [`PEM_write_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509.html 606 to_pem, 607 ffi::PEM_write_bio_X509 608 } 609 610 to_der! { 611 /// Serializes the certificate into a DER-encoded X509 structure. 612 /// 613 /// This corresponds to [`i2d_X509`]. 614 /// 615 /// [`i2d_X509`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509.html 616 to_der, 617 ffi::i2d_X509 618 } 619 } 620 621 impl ToOwned for X509Ref { 622 type Owned = X509; 623 to_owned(&self) -> X509624 fn to_owned(&self) -> X509 { 625 unsafe { 626 X509_up_ref(self.as_ptr()); 627 X509::from_ptr(self.as_ptr()) 628 } 629 } 630 } 631 632 impl X509 { 633 /// Returns a new builder. builder() -> Result<X509Builder, ErrorStack>634 pub fn builder() -> Result<X509Builder, ErrorStack> { 635 X509Builder::new() 636 } 637 638 from_pem! { 639 /// Deserializes a PEM-encoded X509 structure. 640 /// 641 /// The input should have a header of `-----BEGIN CERTIFICATE-----`. 642 /// 643 /// This corresponds to [`PEM_read_bio_X509`]. 644 /// 645 /// [`PEM_read_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509.html 646 from_pem, 647 X509, 648 ffi::PEM_read_bio_X509 649 } 650 651 from_der! { 652 /// Deserializes a DER-encoded X509 structure. 653 /// 654 /// This corresponds to [`d2i_X509`]. 655 /// 656 /// [`d2i_X509`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html 657 from_der, 658 X509, 659 ffi::d2i_X509 660 } 661 662 /// Deserializes a list of PEM-formatted certificates. stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack>663 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> { 664 unsafe { 665 ffi::init(); 666 let bio = MemBioSlice::new(pem)?; 667 668 let mut certs = vec![]; 669 loop { 670 let r = 671 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()); 672 if r.is_null() { 673 let err = ffi::ERR_peek_last_error(); 674 if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM 675 && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE 676 { 677 ffi::ERR_clear_error(); 678 break; 679 } 680 681 return Err(ErrorStack::get()); 682 } else { 683 certs.push(X509(r)); 684 } 685 } 686 687 Ok(certs) 688 } 689 } 690 } 691 692 impl Clone for X509 { clone(&self) -> X509693 fn clone(&self) -> X509 { 694 X509Ref::to_owned(self) 695 } 696 } 697 698 impl fmt::Debug for X509 { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result699 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 700 let serial = match &self.serial_number().to_bn() { 701 Ok(bn) => match bn.to_hex_str() { 702 Ok(hex) => hex.to_string(), 703 Err(_) => "".to_string(), 704 }, 705 Err(_) => "".to_string(), 706 }; 707 let mut debug_struct = formatter.debug_struct("X509"); 708 debug_struct.field("serial_number", &serial); 709 debug_struct.field("signature_algorithm", &self.signature_algorithm().object()); 710 debug_struct.field("issuer", &self.issuer_name()); 711 debug_struct.field("subject", &self.subject_name()); 712 if let Some(subject_alt_names) = &self.subject_alt_names() { 713 debug_struct.field("subject_alt_names", subject_alt_names); 714 } 715 debug_struct.field("not_before", &self.not_before()); 716 debug_struct.field("not_after", &self.not_after()); 717 718 if let Ok(public_key) = &self.public_key() { 719 debug_struct.field("public_key", public_key); 720 }; 721 // TODO: Print extensions once they are supported on the X509 struct. 722 723 debug_struct.finish() 724 } 725 } 726 727 impl AsRef<X509Ref> for X509Ref { as_ref(&self) -> &X509Ref728 fn as_ref(&self) -> &X509Ref { 729 self 730 } 731 } 732 733 impl Stackable for X509 { 734 type StackType = ffi::stack_st_X509; 735 } 736 737 /// A context object required to construct certain `X509` extension values. 738 pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>); 739 740 impl<'a> X509v3Context<'a> { as_ptr(&self) -> *mut ffi::X509V3_CTX741 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX { 742 &self.0 as *const _ as *mut _ 743 } 744 } 745 746 foreign_type_and_impl_send_sync! { 747 type CType = ffi::X509_EXTENSION; 748 fn drop = ffi::X509_EXTENSION_free; 749 750 /// Permit additional fields to be added to an `X509` v3 certificate. 751 pub struct X509Extension; 752 /// Reference to `X509Extension`. 753 pub struct X509ExtensionRef; 754 } 755 756 impl Stackable for X509Extension { 757 type StackType = ffi::stack_st_X509_EXTENSION; 758 } 759 760 impl X509Extension { 761 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported 762 /// names and their value formats. 763 /// 764 /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be 765 /// provided. 766 /// 767 /// See the extension module for builder types which will construct certain common extensions. new( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: &str, value: &str, ) -> Result<X509Extension, ErrorStack>768 pub fn new( 769 conf: Option<&ConfRef>, 770 context: Option<&X509v3Context<'_>>, 771 name: &str, 772 value: &str, 773 ) -> Result<X509Extension, ErrorStack> { 774 let name = CString::new(name).unwrap(); 775 let value = CString::new(value).unwrap(); 776 unsafe { 777 ffi::init(); 778 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); 779 let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); 780 let name = name.as_ptr() as *mut _; 781 let value = value.as_ptr() as *mut _; 782 783 cvt_p(ffi::X509V3_EXT_nconf(conf, context, name, value)).map(X509Extension) 784 } 785 } 786 787 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported 788 /// extensions and their value formats. 789 /// 790 /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to 791 /// be provided. 792 /// 793 /// See the extension module for builder types which will construct certain common extensions. new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: Nid, value: &str, ) -> Result<X509Extension, ErrorStack>794 pub fn new_nid( 795 conf: Option<&ConfRef>, 796 context: Option<&X509v3Context<'_>>, 797 name: Nid, 798 value: &str, 799 ) -> Result<X509Extension, ErrorStack> { 800 let value = CString::new(value).unwrap(); 801 unsafe { 802 ffi::init(); 803 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); 804 let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); 805 let name = name.as_raw(); 806 let value = value.as_ptr() as *mut _; 807 808 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension) 809 } 810 } 811 } 812 813 /// A builder used to construct an `X509Name`. 814 pub struct X509NameBuilder(X509Name); 815 816 impl X509NameBuilder { 817 /// Creates a new builder. new() -> Result<X509NameBuilder, ErrorStack>818 pub fn new() -> Result<X509NameBuilder, ErrorStack> { 819 unsafe { 820 ffi::init(); 821 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p))) 822 } 823 } 824 825 /// Add a field entry by str. 826 /// 827 /// This corresponds to [`X509_NAME_add_entry_by_txt`]. 828 /// 829 /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack>830 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { 831 unsafe { 832 let field = CString::new(field).unwrap(); 833 assert!(value.len() <= c_int::max_value() as usize); 834 cvt(ffi::X509_NAME_add_entry_by_txt( 835 self.0.as_ptr(), 836 field.as_ptr() as *mut _, 837 ffi::MBSTRING_UTF8, 838 value.as_ptr(), 839 value.len() as c_int, 840 -1, 841 0, 842 )) 843 .map(|_| ()) 844 } 845 } 846 847 /// Add a field entry by str with a specific type. 848 /// 849 /// This corresponds to [`X509_NAME_add_entry_by_txt`]. 850 /// 851 /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html append_entry_by_text_with_type( &mut self, field: &str, value: &str, ty: Asn1Type, ) -> Result<(), ErrorStack>852 pub fn append_entry_by_text_with_type( 853 &mut self, 854 field: &str, 855 value: &str, 856 ty: Asn1Type, 857 ) -> Result<(), ErrorStack> { 858 unsafe { 859 let field = CString::new(field).unwrap(); 860 assert!(value.len() <= c_int::max_value() as usize); 861 cvt(ffi::X509_NAME_add_entry_by_txt( 862 self.0.as_ptr(), 863 field.as_ptr() as *mut _, 864 ty.as_raw(), 865 value.as_ptr(), 866 value.len() as c_int, 867 -1, 868 0, 869 )) 870 .map(|_| ()) 871 } 872 } 873 874 /// Add a field entry by NID. 875 /// 876 /// This corresponds to [`X509_NAME_add_entry_by_NID`]. 877 /// 878 /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack>879 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { 880 unsafe { 881 assert!(value.len() <= c_int::max_value() as usize); 882 cvt(ffi::X509_NAME_add_entry_by_NID( 883 self.0.as_ptr(), 884 field.as_raw(), 885 ffi::MBSTRING_UTF8, 886 value.as_ptr() as *mut _, 887 value.len() as c_int, 888 -1, 889 0, 890 )) 891 .map(|_| ()) 892 } 893 } 894 895 /// Add a field entry by NID with a specific type. 896 /// 897 /// This corresponds to [`X509_NAME_add_entry_by_NID`]. 898 /// 899 /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html append_entry_by_nid_with_type( &mut self, field: Nid, value: &str, ty: Asn1Type, ) -> Result<(), ErrorStack>900 pub fn append_entry_by_nid_with_type( 901 &mut self, 902 field: Nid, 903 value: &str, 904 ty: Asn1Type, 905 ) -> Result<(), ErrorStack> { 906 unsafe { 907 assert!(value.len() <= c_int::max_value() as usize); 908 cvt(ffi::X509_NAME_add_entry_by_NID( 909 self.0.as_ptr(), 910 field.as_raw(), 911 ty.as_raw(), 912 value.as_ptr() as *mut _, 913 value.len() as c_int, 914 -1, 915 0, 916 )) 917 .map(|_| ()) 918 } 919 } 920 921 /// Return an `X509Name`. build(self) -> X509Name922 pub fn build(self) -> X509Name { 923 self.0 924 } 925 } 926 927 foreign_type_and_impl_send_sync! { 928 type CType = ffi::X509_NAME; 929 fn drop = ffi::X509_NAME_free; 930 931 /// The names of an `X509` certificate. 932 pub struct X509Name; 933 /// Reference to `X509Name`. 934 pub struct X509NameRef; 935 } 936 937 impl X509Name { 938 /// Returns a new builder. builder() -> Result<X509NameBuilder, ErrorStack>939 pub fn builder() -> Result<X509NameBuilder, ErrorStack> { 940 X509NameBuilder::new() 941 } 942 943 /// Loads subject names from a file containing PEM-formatted certificates. 944 /// 945 /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`. load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack>946 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> { 947 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); 948 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) } 949 } 950 } 951 952 impl Stackable for X509Name { 953 type StackType = ffi::stack_st_X509_NAME; 954 } 955 956 impl X509NameRef { 957 /// Returns the name entries by the nid. entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_>958 pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> { 959 X509NameEntries { 960 name: self, 961 nid: Some(nid), 962 loc: -1, 963 } 964 } 965 966 /// Returns an iterator over all `X509NameEntry` values entries(&self) -> X509NameEntries<'_>967 pub fn entries(&self) -> X509NameEntries<'_> { 968 X509NameEntries { 969 name: self, 970 nid: None, 971 loc: -1, 972 } 973 } 974 } 975 976 impl fmt::Debug for X509NameRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result977 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 978 formatter.debug_list().entries(self.entries()).finish() 979 } 980 } 981 982 /// A type to destructure and examine an `X509Name`. 983 pub struct X509NameEntries<'a> { 984 name: &'a X509NameRef, 985 nid: Option<Nid>, 986 loc: c_int, 987 } 988 989 impl<'a> Iterator for X509NameEntries<'a> { 990 type Item = &'a X509NameEntryRef; 991 next(&mut self) -> Option<&'a X509NameEntryRef>992 fn next(&mut self) -> Option<&'a X509NameEntryRef> { 993 unsafe { 994 match self.nid { 995 Some(nid) => { 996 // There is a `Nid` specified to search for 997 self.loc = 998 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc); 999 if self.loc == -1 { 1000 return None; 1001 } 1002 } 1003 None => { 1004 // Iterate over all `Nid`s 1005 self.loc += 1; 1006 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) { 1007 return None; 1008 } 1009 } 1010 } 1011 1012 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); 1013 1014 Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null")) 1015 } 1016 } 1017 } 1018 1019 foreign_type_and_impl_send_sync! { 1020 type CType = ffi::X509_NAME_ENTRY; 1021 fn drop = ffi::X509_NAME_ENTRY_free; 1022 1023 /// A name entry associated with a `X509Name`. 1024 pub struct X509NameEntry; 1025 /// Reference to `X509NameEntry`. 1026 pub struct X509NameEntryRef; 1027 } 1028 1029 impl X509NameEntryRef { 1030 /// Returns the field value of an `X509NameEntry`. 1031 /// 1032 /// This corresponds to [`X509_NAME_ENTRY_get_data`]. 1033 /// 1034 /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html data(&self) -> &Asn1StringRef1035 pub fn data(&self) -> &Asn1StringRef { 1036 unsafe { 1037 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); 1038 Asn1StringRef::from_ptr(data) 1039 } 1040 } 1041 1042 /// Returns the `Asn1Object` value of an `X509NameEntry`. 1043 /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`. 1044 /// 1045 /// This corresponds to [`X509_NAME_ENTRY_get_object`]. 1046 /// 1047 /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html object(&self) -> &Asn1ObjectRef1048 pub fn object(&self) -> &Asn1ObjectRef { 1049 unsafe { 1050 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); 1051 Asn1ObjectRef::from_ptr(object) 1052 } 1053 } 1054 } 1055 1056 impl fmt::Debug for X509NameEntryRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1057 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1058 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data())) 1059 } 1060 } 1061 1062 /// A builder used to construct an `X509Req`. 1063 pub struct X509ReqBuilder(X509Req); 1064 1065 impl X509ReqBuilder { 1066 /// Returns a builder for a certificate request. 1067 /// 1068 /// This corresponds to [`X509_REQ_new`]. 1069 /// 1070 ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html new() -> Result<X509ReqBuilder, ErrorStack>1071 pub fn new() -> Result<X509ReqBuilder, ErrorStack> { 1072 unsafe { 1073 ffi::init(); 1074 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) 1075 } 1076 } 1077 1078 /// Set the numerical value of the version field. 1079 /// 1080 /// This corresponds to [`X509_REQ_set_version`]. 1081 /// 1082 ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html set_version(&mut self, version: i32) -> Result<(), ErrorStack>1083 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { 1084 unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } 1085 } 1086 1087 /// Set the issuer name. 1088 /// 1089 /// This corresponds to [`X509_REQ_set_subject_name`]. 1090 /// 1091 /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_subject_name.html set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>1092 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { 1093 unsafe { 1094 cvt(ffi::X509_REQ_set_subject_name( 1095 self.0.as_ptr(), 1096 subject_name.as_ptr(), 1097 )) 1098 .map(|_| ()) 1099 } 1100 } 1101 1102 /// Set the public key. 1103 /// 1104 /// This corresponds to [`X509_REQ_set_pubkey`]. 1105 /// 1106 /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_pubkey.html set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,1107 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> 1108 where 1109 T: HasPublic, 1110 { 1111 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } 1112 } 1113 1114 /// Return an `X509v3Context`. This context object can be used to construct 1115 /// certain `X509` extensions. x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a>1116 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> { 1117 unsafe { 1118 let mut ctx = mem::zeroed(); 1119 1120 ffi::X509V3_set_ctx( 1121 &mut ctx, 1122 ptr::null_mut(), 1123 ptr::null_mut(), 1124 self.0.as_ptr(), 1125 ptr::null_mut(), 1126 0, 1127 ); 1128 1129 // nodb case taken care of since we zeroed ctx above 1130 if let Some(conf) = conf { 1131 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); 1132 } 1133 1134 X509v3Context(ctx, PhantomData) 1135 } 1136 } 1137 1138 /// Permits any number of extension fields to be added to the certificate. add_extensions( &mut self, extensions: &StackRef<X509Extension>, ) -> Result<(), ErrorStack>1139 pub fn add_extensions( 1140 &mut self, 1141 extensions: &StackRef<X509Extension>, 1142 ) -> Result<(), ErrorStack> { 1143 unsafe { 1144 cvt(ffi::X509_REQ_add_extensions( 1145 self.0.as_ptr(), 1146 extensions.as_ptr(), 1147 )) 1148 .map(|_| ()) 1149 } 1150 } 1151 1152 /// Sign the request using a private key. 1153 /// 1154 /// This corresponds to [`X509_REQ_sign`]. 1155 /// 1156 /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,1157 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> 1158 where 1159 T: HasPrivate, 1160 { 1161 unsafe { 1162 cvt(ffi::X509_REQ_sign( 1163 self.0.as_ptr(), 1164 key.as_ptr(), 1165 hash.as_ptr(), 1166 )) 1167 .map(|_| ()) 1168 } 1169 } 1170 1171 /// Returns the `X509Req`. build(self) -> X509Req1172 pub fn build(self) -> X509Req { 1173 self.0 1174 } 1175 } 1176 1177 foreign_type_and_impl_send_sync! { 1178 type CType = ffi::X509_REQ; 1179 fn drop = ffi::X509_REQ_free; 1180 1181 /// An `X509` certificate request. 1182 pub struct X509Req; 1183 /// Reference to `X509Req`. 1184 pub struct X509ReqRef; 1185 } 1186 1187 impl X509Req { 1188 /// A builder for `X509Req`. builder() -> Result<X509ReqBuilder, ErrorStack>1189 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> { 1190 X509ReqBuilder::new() 1191 } 1192 1193 from_pem! { 1194 /// Deserializes a PEM-encoded PKCS#10 certificate request structure. 1195 /// 1196 /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`. 1197 /// 1198 /// This corresponds to [`PEM_read_bio_X509_REQ`]. 1199 /// 1200 /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html 1201 from_pem, 1202 X509Req, 1203 ffi::PEM_read_bio_X509_REQ 1204 } 1205 1206 from_der! { 1207 /// Deserializes a DER-encoded PKCS#10 certificate request structure. 1208 /// 1209 /// This corresponds to [`d2i_X509_REQ`]. 1210 /// 1211 /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html 1212 from_der, 1213 X509Req, 1214 ffi::d2i_X509_REQ 1215 } 1216 } 1217 1218 impl X509ReqRef { 1219 to_pem! { 1220 /// Serializes the certificate request to a PEM-encoded PKCS#10 structure. 1221 /// 1222 /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`. 1223 /// 1224 /// This corresponds to [`PEM_write_bio_X509_REQ`]. 1225 /// 1226 /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html 1227 to_pem, 1228 ffi::PEM_write_bio_X509_REQ 1229 } 1230 1231 to_der! { 1232 /// Serializes the certificate request to a DER-encoded PKCS#10 structure. 1233 /// 1234 /// This corresponds to [`i2d_X509_REQ`]. 1235 /// 1236 /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html 1237 to_der, 1238 ffi::i2d_X509_REQ 1239 } 1240 1241 /// Returns the numerical value of the version field of the certificate request. 1242 /// 1243 /// This corresponds to [`X509_REQ_get_version`] 1244 /// 1245 /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html version(&self) -> i321246 pub fn version(&self) -> i32 { 1247 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } 1248 } 1249 1250 /// Returns the subject name of the certificate request. 1251 /// 1252 /// This corresponds to [`X509_REQ_get_subject_name`] 1253 /// 1254 /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html subject_name(&self) -> &X509NameRef1255 pub fn subject_name(&self) -> &X509NameRef { 1256 unsafe { 1257 let name = X509_REQ_get_subject_name(self.as_ptr()); 1258 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") 1259 } 1260 } 1261 1262 /// Returns the public key of the certificate request. 1263 /// 1264 /// This corresponds to [`X509_REQ_get_pubkey"] 1265 /// 1266 /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html public_key(&self) -> Result<PKey<Public>, ErrorStack>1267 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> { 1268 unsafe { 1269 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?; 1270 Ok(PKey::from_ptr(key)) 1271 } 1272 } 1273 1274 /// Check if the certificate request is signed using the given public key. 1275 /// 1276 /// Returns `true` if verification succeeds. 1277 /// 1278 /// This corresponds to [`X509_REQ_verify"]. 1279 /// 1280 /// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,1281 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 1282 where 1283 T: HasPublic, 1284 { 1285 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 1286 } 1287 1288 /// Returns the extensions of the certificate request. 1289 /// 1290 /// This corresponds to [`X509_REQ_get_extensions"] extensions(&self) -> Result<Stack<X509Extension>, ErrorStack>1291 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> { 1292 unsafe { 1293 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?; 1294 Ok(Stack::from_ptr(extensions)) 1295 } 1296 } 1297 } 1298 1299 /// The result of peer certificate verification. 1300 #[derive(Copy, Clone, PartialEq, Eq)] 1301 pub struct X509VerifyResult(c_int); 1302 1303 impl fmt::Debug for X509VerifyResult { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1304 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 1305 fmt.debug_struct("X509VerifyResult") 1306 .field("code", &self.0) 1307 .field("error", &self.error_string()) 1308 .finish() 1309 } 1310 } 1311 1312 impl fmt::Display for X509VerifyResult { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1313 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 1314 fmt.write_str(self.error_string()) 1315 } 1316 } 1317 1318 impl Error for X509VerifyResult {} 1319 1320 impl X509VerifyResult { 1321 /// Creates an `X509VerifyResult` from a raw error number. 1322 /// 1323 /// # Safety 1324 /// 1325 /// Some methods on `X509VerifyResult` are not thread safe if the error 1326 /// number is invalid. from_raw(err: c_int) -> X509VerifyResult1327 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult { 1328 X509VerifyResult(err) 1329 } 1330 1331 /// Return the integer representation of an `X509VerifyResult`. 1332 #[allow(clippy::trivially_copy_pass_by_ref)] as_raw(&self) -> c_int1333 pub fn as_raw(&self) -> c_int { 1334 self.0 1335 } 1336 1337 /// Return a human readable error string from the verification error. 1338 /// 1339 /// This corresponds to [`X509_verify_cert_error_string`]. 1340 /// 1341 /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify_cert_error_string.html 1342 #[allow(clippy::trivially_copy_pass_by_ref)] error_string(&self) -> &'static str1343 pub fn error_string(&self) -> &'static str { 1344 ffi::init(); 1345 1346 unsafe { 1347 let s = ffi::X509_verify_cert_error_string(self.0 as c_long); 1348 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() 1349 } 1350 } 1351 1352 /// Successful peer certifiate verification. 1353 pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK); 1354 /// Application verification failure. 1355 pub const APPLICATION_VERIFICATION: X509VerifyResult = 1356 X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION); 1357 } 1358 1359 foreign_type_and_impl_send_sync! { 1360 type CType = ffi::GENERAL_NAME; 1361 fn drop = ffi::GENERAL_NAME_free; 1362 1363 /// An `X509` certificate alternative names. 1364 pub struct GeneralName; 1365 /// Reference to `GeneralName`. 1366 pub struct GeneralNameRef; 1367 } 1368 1369 impl GeneralNameRef { ia5_string(&self, ffi_type: c_int) -> Option<&str>1370 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { 1371 unsafe { 1372 if (*self.as_ptr()).type_ != ffi_type { 1373 return None; 1374 } 1375 1376 let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); 1377 let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); 1378 1379 let slice = slice::from_raw_parts(ptr as *const u8, len as usize); 1380 // IA5Strings are stated to be ASCII (specifically IA5). Hopefully 1381 // OpenSSL checks that when loading a certificate but if not we'll 1382 // use this instead of from_utf8_unchecked just in case. 1383 str::from_utf8(slice).ok() 1384 } 1385 } 1386 1387 /// Returns the contents of this `GeneralName` if it is an `rfc822Name`. email(&self) -> Option<&str>1388 pub fn email(&self) -> Option<&str> { 1389 self.ia5_string(ffi::GEN_EMAIL) 1390 } 1391 1392 /// Returns the contents of this `GeneralName` if it is a `dNSName`. dnsname(&self) -> Option<&str>1393 pub fn dnsname(&self) -> Option<&str> { 1394 self.ia5_string(ffi::GEN_DNS) 1395 } 1396 1397 /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`. uri(&self) -> Option<&str>1398 pub fn uri(&self) -> Option<&str> { 1399 self.ia5_string(ffi::GEN_URI) 1400 } 1401 1402 /// Returns the contents of this `GeneralName` if it is an `iPAddress`. ipaddress(&self) -> Option<&[u8]>1403 pub fn ipaddress(&self) -> Option<&[u8]> { 1404 unsafe { 1405 if (*self.as_ptr()).type_ != ffi::GEN_IPADD { 1406 return None; 1407 } 1408 1409 let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); 1410 let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); 1411 1412 Some(slice::from_raw_parts(ptr as *const u8, len as usize)) 1413 } 1414 } 1415 } 1416 1417 impl fmt::Debug for GeneralNameRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1418 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1419 if let Some(email) = self.email() { 1420 formatter.write_str(email) 1421 } else if let Some(dnsname) = self.dnsname() { 1422 formatter.write_str(dnsname) 1423 } else if let Some(uri) = self.uri() { 1424 formatter.write_str(uri) 1425 } else if let Some(ipaddress) = self.ipaddress() { 1426 let result = String::from_utf8_lossy(ipaddress); 1427 formatter.write_str(&result) 1428 } else { 1429 formatter.write_str("(empty)") 1430 } 1431 } 1432 } 1433 1434 impl Stackable for GeneralName { 1435 type StackType = ffi::stack_st_GENERAL_NAME; 1436 } 1437 1438 foreign_type_and_impl_send_sync! { 1439 type CType = ffi::ACCESS_DESCRIPTION; 1440 fn drop = ffi::ACCESS_DESCRIPTION_free; 1441 1442 /// `AccessDescription` of certificate authority information. 1443 pub struct AccessDescription; 1444 /// Reference to `AccessDescription`. 1445 pub struct AccessDescriptionRef; 1446 } 1447 1448 impl AccessDescriptionRef { 1449 /// Returns the access method OID. method(&self) -> &Asn1ObjectRef1450 pub fn method(&self) -> &Asn1ObjectRef { 1451 unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) } 1452 } 1453 1454 // Returns the access location. location(&self) -> &GeneralNameRef1455 pub fn location(&self) -> &GeneralNameRef { 1456 unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) } 1457 } 1458 } 1459 1460 impl Stackable for AccessDescription { 1461 type StackType = ffi::stack_st_ACCESS_DESCRIPTION; 1462 } 1463 1464 foreign_type_and_impl_send_sync! { 1465 type CType = ffi::X509_ALGOR; 1466 fn drop = ffi::X509_ALGOR_free; 1467 1468 /// An `X509` certificate signature algorithm. 1469 pub struct X509Algorithm; 1470 /// Reference to `X509Algorithm`. 1471 pub struct X509AlgorithmRef; 1472 } 1473 1474 impl X509AlgorithmRef { 1475 /// Returns the ASN.1 OID of this algorithm. object(&self) -> &Asn1ObjectRef1476 pub fn object(&self) -> &Asn1ObjectRef { 1477 unsafe { 1478 let mut oid = ptr::null(); 1479 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); 1480 Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null") 1481 } 1482 } 1483 } 1484 1485 foreign_type_and_impl_send_sync! { 1486 type CType = ffi::X509_OBJECT; 1487 fn drop = X509_OBJECT_free; 1488 1489 /// An `X509` or an X509 certificate revocation list. 1490 pub struct X509Object; 1491 /// Reference to `X509Object` 1492 pub struct X509ObjectRef; 1493 } 1494 1495 impl X509ObjectRef { x509(&self) -> Option<&X509Ref>1496 pub fn x509(&self) -> Option<&X509Ref> { 1497 unsafe { 1498 let ptr = X509_OBJECT_get0_X509(self.as_ptr()); 1499 X509Ref::from_const_ptr_opt(ptr) 1500 } 1501 } 1502 } 1503 1504 impl Stackable for X509Object { 1505 type StackType = ffi::stack_st_X509_OBJECT; 1506 } 1507 1508 cfg_if! { 1509 if #[cfg(any(ossl110, libressl273))] { 1510 use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature}; 1511 } else { 1512 #[allow(bad_style)] 1513 unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { 1514 (*(*(*x).cert_info).validity).notAfter 1515 } 1516 1517 #[allow(bad_style)] 1518 unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { 1519 (*(*(*x).cert_info).validity).notBefore 1520 } 1521 1522 #[allow(bad_style)] 1523 unsafe fn X509_up_ref(x: *mut ffi::X509) { 1524 ffi::CRYPTO_add_lock( 1525 &mut (*x).references, 1526 1, 1527 ffi::CRYPTO_LOCK_X509, 1528 "mod.rs\0".as_ptr() as *const _, 1529 line!() as c_int, 1530 ); 1531 } 1532 1533 #[allow(bad_style)] 1534 unsafe fn X509_get0_signature( 1535 psig: *mut *const ffi::ASN1_BIT_STRING, 1536 palg: *mut *const ffi::X509_ALGOR, 1537 x: *const ffi::X509, 1538 ) { 1539 if !psig.is_null() { 1540 *psig = (*x).signature; 1541 } 1542 if !palg.is_null() { 1543 *palg = (*x).sig_alg; 1544 } 1545 } 1546 } 1547 } 1548 1549 cfg_if! { 1550 if #[cfg(ossl110)] { 1551 use ffi::{ 1552 X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter, 1553 X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name, 1554 }; 1555 } else { 1556 use ffi::{ 1557 ASN1_STRING_data as ASN1_STRING_get0_data, 1558 X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, 1559 X509_set_notAfter as X509_set1_notAfter, 1560 X509_set_notBefore as X509_set1_notBefore, 1561 }; 1562 1563 #[allow(bad_style)] 1564 unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { 1565 ffi::ASN1_INTEGER_get((*(*x).req_info).version) 1566 } 1567 1568 #[allow(bad_style)] 1569 unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { 1570 (*(*x).req_info).subject 1571 } 1572 1573 #[allow(bad_style)] 1574 unsafe fn X509_ALGOR_get0( 1575 paobj: *mut *const ffi::ASN1_OBJECT, 1576 pptype: *mut c_int, 1577 pval: *mut *mut ::libc::c_void, 1578 alg: *const ffi::X509_ALGOR, 1579 ) { 1580 if !paobj.is_null() { 1581 *paobj = (*alg).algorithm; 1582 } 1583 assert!(pptype.is_null()); 1584 assert!(pval.is_null()); 1585 } 1586 } 1587 } 1588 1589 cfg_if! { 1590 if #[cfg(any(ossl110, libressl270))] { 1591 use ffi::X509_OBJECT_get0_X509; 1592 } else { 1593 #[allow(bad_style)] 1594 unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 { 1595 if (*x).type_ == ffi::X509_LU_X509 { 1596 (*x).data.x509 1597 } else { 1598 ptr::null_mut() 1599 } 1600 } 1601 } 1602 } 1603 1604 cfg_if! { 1605 if #[cfg(ossl110)] { 1606 use ffi::X509_OBJECT_free; 1607 } else { 1608 #[allow(bad_style)] 1609 unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) { 1610 ffi::X509_OBJECT_free_contents(x); 1611 ffi::CRYPTO_free(x as *mut libc::c_void); 1612 } 1613 } 1614 } 1615