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, Opaque}; 12 use libc::{c_int, c_long, c_uint}; 13 use std::cmp::{self, Ordering}; 14 use std::convert::TryFrom; 15 use std::error::Error; 16 use std::ffi::{CStr, CString}; 17 use std::fmt; 18 use std::marker::PhantomData; 19 use std::mem; 20 use std::net::IpAddr; 21 use std::path::Path; 22 use std::ptr; 23 use std::slice; 24 use std::str; 25 26 use crate::asn1::{ 27 Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef, Asn1Type, 28 }; 29 use crate::bio::MemBioSlice; 30 use crate::conf::ConfRef; 31 use crate::error::ErrorStack; 32 use crate::ex_data::Index; 33 use crate::hash::{DigestBytes, MessageDigest}; 34 use crate::nid::Nid; 35 use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; 36 use crate::ssl::SslRef; 37 use crate::stack::{Stack, StackRef, Stackable}; 38 use crate::string::OpensslString; 39 use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; 40 use crate::{cvt, cvt_n, cvt_p}; 41 use openssl_macros::corresponds; 42 43 #[cfg(any(ossl102, libressl261))] 44 pub mod verify; 45 46 pub mod extension; 47 pub mod store; 48 49 #[cfg(test)] 50 mod tests; 51 52 foreign_type_and_impl_send_sync! { 53 type CType = ffi::X509_STORE_CTX; 54 fn drop = ffi::X509_STORE_CTX_free; 55 56 /// An `X509` certificate store context. 57 pub struct X509StoreContext; 58 59 /// A reference to an [`X509StoreContext`]. 60 pub struct X509StoreContextRef; 61 } 62 63 impl X509StoreContext { 64 /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a 65 /// context. 66 #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)] ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack>67 pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> { 68 unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) } 69 } 70 71 /// Creates a new `X509StoreContext` instance. 72 #[corresponds(X509_STORE_CTX_new)] new() -> Result<X509StoreContext, ErrorStack>73 pub fn new() -> Result<X509StoreContext, ErrorStack> { 74 unsafe { 75 ffi::init(); 76 cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext) 77 } 78 } 79 } 80 81 impl X509StoreContextRef { 82 /// Returns application data pertaining to an `X509` store context. 83 #[corresponds(X509_STORE_CTX_get_ex_data)] ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T>84 pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> { 85 unsafe { 86 let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw()); 87 if data.is_null() { 88 None 89 } else { 90 Some(&*(data as *const T)) 91 } 92 } 93 } 94 95 /// Returns the error code of the context. 96 #[corresponds(X509_STORE_CTX_get_error)] error(&self) -> X509VerifyResult97 pub fn error(&self) -> X509VerifyResult { 98 unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) } 99 } 100 101 /// Initializes this context with the given certificate, certificates chain and certificate 102 /// store. After initializing the context, the `with_context` closure is called with the prepared 103 /// context. As long as the closure is running, the context stays initialized and can be used 104 /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished. 105 /// 106 /// * `trust` - The certificate store with the trusted certificates. 107 /// * `cert` - The certificate that should be verified. 108 /// * `cert_chain` - The certificates chain. 109 /// * `with_context` - The closure that is called with the initialized context. 110 /// 111 /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to 112 /// [`X509_STORE_CTX_cleanup`] after calling `with_context`. 113 /// 114 /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_init.html 115 /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/manmaster/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>,116 pub fn init<F, T>( 117 &mut self, 118 trust: &store::X509StoreRef, 119 cert: &X509Ref, 120 cert_chain: &StackRef<X509>, 121 with_context: F, 122 ) -> Result<T, ErrorStack> 123 where 124 F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>, 125 { 126 struct Cleanup<'a>(&'a mut X509StoreContextRef); 127 128 impl<'a> Drop for Cleanup<'a> { 129 fn drop(&mut self) { 130 unsafe { 131 ffi::X509_STORE_CTX_cleanup(self.0.as_ptr()); 132 } 133 } 134 } 135 136 unsafe { 137 cvt(ffi::X509_STORE_CTX_init( 138 self.as_ptr(), 139 trust.as_ptr(), 140 cert.as_ptr(), 141 cert_chain.as_ptr(), 142 ))?; 143 144 let cleanup = Cleanup(self); 145 with_context(cleanup.0) 146 } 147 } 148 149 /// Verifies the stored certificate. 150 /// 151 /// Returns `true` if verification succeeds. The `error` method will return the specific 152 /// validation error if the certificate was not valid. 153 /// 154 /// This will only work inside of a call to `init`. 155 #[corresponds(X509_verify_cert)] verify_cert(&mut self) -> Result<bool, ErrorStack>156 pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> { 157 unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) } 158 } 159 160 /// Set the error code of the context. 161 #[corresponds(X509_STORE_CTX_set_error)] set_error(&mut self, result: X509VerifyResult)162 pub fn set_error(&mut self, result: X509VerifyResult) { 163 unsafe { 164 ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw()); 165 } 166 } 167 168 /// Returns a reference to the certificate which caused the error or None if 169 /// no certificate is relevant to the error. 170 #[corresponds(X509_STORE_CTX_get_current_cert)] current_cert(&self) -> Option<&X509Ref>171 pub fn current_cert(&self) -> Option<&X509Ref> { 172 unsafe { 173 let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr()); 174 X509Ref::from_const_ptr_opt(ptr) 175 } 176 } 177 178 /// Returns a non-negative integer representing the depth in the certificate 179 /// chain where the error occurred. If it is zero it occurred in the end 180 /// entity certificate, one if it is the certificate which signed the end 181 /// entity certificate and so on. 182 #[corresponds(X509_STORE_CTX_get_error_depth)] error_depth(&self) -> u32183 pub fn error_depth(&self) -> u32 { 184 unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 } 185 } 186 187 /// Returns a reference to a complete valid `X509` certificate chain. 188 #[corresponds(X509_STORE_CTX_get0_chain)] chain(&self) -> Option<&StackRef<X509>>189 pub fn chain(&self) -> Option<&StackRef<X509>> { 190 unsafe { 191 let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); 192 193 if chain.is_null() { 194 None 195 } else { 196 Some(StackRef::from_ptr(chain)) 197 } 198 } 199 } 200 } 201 202 /// A builder used to construct an `X509`. 203 pub struct X509Builder(X509); 204 205 impl X509Builder { 206 /// Creates a new builder. 207 #[corresponds(X509_new)] new() -> Result<X509Builder, ErrorStack>208 pub fn new() -> Result<X509Builder, ErrorStack> { 209 unsafe { 210 ffi::init(); 211 cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p))) 212 } 213 } 214 215 /// Sets the notAfter constraint on the certificate. 216 #[corresponds(X509_set1_notAfter)] set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack>217 pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { 218 unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } 219 } 220 221 /// Sets the notBefore constraint on the certificate. 222 #[corresponds(X509_set1_notBefore)] set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack>223 pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { 224 unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } 225 } 226 227 /// Sets the version of the certificate. 228 /// 229 /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of 230 /// the X.509 standard should pass `2` to this method. 231 #[corresponds(X509_set_version)] 232 #[allow(clippy::useless_conversion)] set_version(&mut self, version: i32) -> Result<(), ErrorStack>233 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { 234 unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) } 235 } 236 237 /// Sets the serial number of the certificate. 238 #[corresponds(X509_set_serialNumber)] set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack>239 pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> { 240 unsafe { 241 cvt(ffi::X509_set_serialNumber( 242 self.0.as_ptr(), 243 serial_number.as_ptr(), 244 )) 245 .map(|_| ()) 246 } 247 } 248 249 /// Sets the issuer name of the certificate. 250 #[corresponds(X509_set_issuer_name)] set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack>251 pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> { 252 unsafe { 253 cvt(ffi::X509_set_issuer_name( 254 self.0.as_ptr(), 255 issuer_name.as_ptr(), 256 )) 257 .map(|_| ()) 258 } 259 } 260 261 /// Sets the subject name of the certificate. 262 /// 263 /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools. 264 /// The `CN` field is used for the common name, such as a DNS name. 265 /// 266 /// ``` 267 /// use openssl::x509::{X509, X509NameBuilder}; 268 /// 269 /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap(); 270 /// x509_name.append_entry_by_text("C", "US").unwrap(); 271 /// x509_name.append_entry_by_text("ST", "CA").unwrap(); 272 /// x509_name.append_entry_by_text("O", "Some organization").unwrap(); 273 /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap(); 274 /// let x509_name = x509_name.build(); 275 /// 276 /// let mut x509 = openssl::x509::X509::builder().unwrap(); 277 /// x509.set_subject_name(&x509_name).unwrap(); 278 /// ``` 279 #[corresponds(X509_set_subject_name)] set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>280 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { 281 unsafe { 282 cvt(ffi::X509_set_subject_name( 283 self.0.as_ptr(), 284 subject_name.as_ptr(), 285 )) 286 .map(|_| ()) 287 } 288 } 289 290 /// Sets the public key associated with the certificate. 291 #[corresponds(X509_set_pubkey)] set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,292 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> 293 where 294 T: HasPublic, 295 { 296 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } 297 } 298 299 /// Returns a context object which is needed to create certain X509 extension values. 300 /// 301 /// Set `issuer` to `None` if the certificate will be self-signed. 302 #[corresponds(X509V3_set_ctx)] x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, conf: Option<&'a ConfRef>, ) -> X509v3Context<'a>303 pub fn x509v3_context<'a>( 304 &'a self, 305 issuer: Option<&'a X509Ref>, 306 conf: Option<&'a ConfRef>, 307 ) -> X509v3Context<'a> { 308 unsafe { 309 let mut ctx = mem::zeroed(); 310 311 let issuer = match issuer { 312 Some(issuer) => issuer.as_ptr(), 313 None => self.0.as_ptr(), 314 }; 315 let subject = self.0.as_ptr(); 316 ffi::X509V3_set_ctx( 317 &mut ctx, 318 issuer, 319 subject, 320 ptr::null_mut(), 321 ptr::null_mut(), 322 0, 323 ); 324 325 // nodb case taken care of since we zeroed ctx above 326 if let Some(conf) = conf { 327 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); 328 } 329 330 X509v3Context(ctx, PhantomData) 331 } 332 } 333 334 /// Adds an X509 extension value to the certificate. 335 /// 336 /// This works just as `append_extension` except it takes ownership of the `X509Extension`. append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack>337 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> { 338 self.append_extension2(&extension) 339 } 340 341 /// Adds an X509 extension value to the certificate. 342 #[corresponds(X509_add_ext)] append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack>343 pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> { 344 unsafe { 345 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; 346 Ok(()) 347 } 348 } 349 350 /// Signs the certificate with a private key. 351 #[corresponds(X509_sign)] sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,352 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> 353 where 354 T: HasPrivate, 355 { 356 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) } 357 } 358 359 /// Consumes the builder, returning the certificate. build(self) -> X509360 pub fn build(self) -> X509 { 361 self.0 362 } 363 } 364 365 foreign_type_and_impl_send_sync! { 366 type CType = ffi::X509; 367 fn drop = ffi::X509_free; 368 369 /// An `X509` public key certificate. 370 pub struct X509; 371 /// Reference to `X509`. 372 pub struct X509Ref; 373 } 374 375 #[cfg(boringssl)] 376 type X509LenTy = c_uint; 377 #[cfg(not(boringssl))] 378 type X509LenTy = c_int; 379 380 impl X509Ref { 381 /// Returns this certificate's subject name. 382 #[corresponds(X509_get_subject_name)] subject_name(&self) -> &X509NameRef383 pub fn subject_name(&self) -> &X509NameRef { 384 unsafe { 385 let name = ffi::X509_get_subject_name(self.as_ptr()); 386 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") 387 } 388 } 389 390 /// Returns the hash of the certificates subject 391 #[corresponds(X509_subject_name_hash)] subject_name_hash(&self) -> u32392 pub fn subject_name_hash(&self) -> u32 { 393 unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } 394 } 395 396 /// Returns this certificate's issuer name. 397 #[corresponds(X509_get_issuer_name)] issuer_name(&self) -> &X509NameRef398 pub fn issuer_name(&self) -> &X509NameRef { 399 unsafe { 400 let name = ffi::X509_get_issuer_name(self.as_ptr()); 401 X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null") 402 } 403 } 404 405 /// Returns the hash of the certificates issuer 406 #[corresponds(X509_issuer_name_hash)] issuer_name_hash(&self) -> u32407 pub fn issuer_name_hash(&self) -> u32 { 408 unsafe { ffi::X509_issuer_name_hash(self.as_ptr()) as u32 } 409 } 410 411 /// Returns this certificate's subject alternative name entries, if they exist. 412 #[corresponds(X509_get_ext_d2i)] subject_alt_names(&self) -> Option<Stack<GeneralName>>413 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> { 414 unsafe { 415 let stack = ffi::X509_get_ext_d2i( 416 self.as_ptr(), 417 ffi::NID_subject_alt_name, 418 ptr::null_mut(), 419 ptr::null_mut(), 420 ); 421 Stack::from_ptr_opt(stack as *mut _) 422 } 423 } 424 425 /// Returns this certificate's issuer alternative name entries, if they exist. 426 #[corresponds(X509_get_ext_d2i)] issuer_alt_names(&self) -> Option<Stack<GeneralName>>427 pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> { 428 unsafe { 429 let stack = ffi::X509_get_ext_d2i( 430 self.as_ptr(), 431 ffi::NID_issuer_alt_name, 432 ptr::null_mut(), 433 ptr::null_mut(), 434 ); 435 Stack::from_ptr_opt(stack as *mut _) 436 } 437 } 438 439 /// Returns this certificate's [`authority information access`] entries, if they exist. 440 /// 441 /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1 442 #[corresponds(X509_get_ext_d2i)] authority_info(&self) -> Option<Stack<AccessDescription>>443 pub fn authority_info(&self) -> Option<Stack<AccessDescription>> { 444 unsafe { 445 let stack = ffi::X509_get_ext_d2i( 446 self.as_ptr(), 447 ffi::NID_info_access, 448 ptr::null_mut(), 449 ptr::null_mut(), 450 ); 451 Stack::from_ptr_opt(stack as *mut _) 452 } 453 } 454 455 #[corresponds(X509_get_pubkey)] public_key(&self) -> Result<PKey<Public>, ErrorStack>456 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> { 457 unsafe { 458 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?; 459 Ok(PKey::from_ptr(pkey)) 460 } 461 } 462 463 /// Returns a digest of the DER representation of the certificate. 464 #[corresponds(X509_digest)] digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack>465 pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> { 466 unsafe { 467 let mut digest = DigestBytes { 468 buf: [0; ffi::EVP_MAX_MD_SIZE as usize], 469 len: ffi::EVP_MAX_MD_SIZE as usize, 470 }; 471 let mut len = ffi::EVP_MAX_MD_SIZE as c_uint; 472 cvt(ffi::X509_digest( 473 self.as_ptr(), 474 hash_type.as_ptr(), 475 digest.buf.as_mut_ptr() as *mut _, 476 &mut len, 477 ))?; 478 digest.len = len as usize; 479 480 Ok(digest) 481 } 482 } 483 484 #[deprecated(since = "0.10.9", note = "renamed to digest")] fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack>485 pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> { 486 self.digest(hash_type).map(|b| b.to_vec()) 487 } 488 489 /// Returns the certificate's Not After validity period. 490 #[corresponds(X509_getm_notAfter)] not_after(&self) -> &Asn1TimeRef491 pub fn not_after(&self) -> &Asn1TimeRef { 492 unsafe { 493 let date = X509_getm_notAfter(self.as_ptr()); 494 Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null") 495 } 496 } 497 498 /// Returns the certificate's Not Before validity period. 499 #[corresponds(X509_getm_notBefore)] not_before(&self) -> &Asn1TimeRef500 pub fn not_before(&self) -> &Asn1TimeRef { 501 unsafe { 502 let date = X509_getm_notBefore(self.as_ptr()); 503 Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null") 504 } 505 } 506 507 /// Returns the certificate's signature 508 #[corresponds(X509_get0_signature)] signature(&self) -> &Asn1BitStringRef509 pub fn signature(&self) -> &Asn1BitStringRef { 510 unsafe { 511 let mut signature = ptr::null(); 512 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); 513 Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null") 514 } 515 } 516 517 /// Returns the certificate's signature algorithm. 518 #[corresponds(X509_get0_signature)] signature_algorithm(&self) -> &X509AlgorithmRef519 pub fn signature_algorithm(&self) -> &X509AlgorithmRef { 520 unsafe { 521 let mut algor = ptr::null(); 522 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); 523 X509AlgorithmRef::from_const_ptr_opt(algor) 524 .expect("signature algorithm must not be null") 525 } 526 } 527 528 /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information 529 /// Access field. 530 #[corresponds(X509_get1_ocsp)] ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack>531 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> { 532 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) } 533 } 534 535 /// Checks that this certificate issued `subject`. 536 #[corresponds(X509_check_issued)] issued(&self, subject: &X509Ref) -> X509VerifyResult537 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult { 538 unsafe { 539 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr()); 540 X509VerifyResult::from_raw(r) 541 } 542 } 543 544 /// Returns certificate version. If this certificate has no explicit version set, it defaults to 545 /// version 1. 546 /// 547 /// Note that `0` return value stands for version 1, `1` for version 2 and so on. 548 #[corresponds(X509_get_version)] 549 #[cfg(ossl110)] version(&self) -> i32550 pub fn version(&self) -> i32 { 551 unsafe { ffi::X509_get_version(self.as_ptr()) as i32 } 552 } 553 554 /// Check if the certificate is signed using the given public key. 555 /// 556 /// Only the signature is checked: no other checks (such as certificate chain validity) 557 /// are performed. 558 /// 559 /// Returns `true` if verification succeeds. 560 #[corresponds(X509_verify)] verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,561 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 562 where 563 T: HasPublic, 564 { 565 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 566 } 567 568 /// Returns this certificate's serial number. 569 #[corresponds(X509_get_serialNumber)] serial_number(&self) -> &Asn1IntegerRef570 pub fn serial_number(&self) -> &Asn1IntegerRef { 571 unsafe { 572 let r = ffi::X509_get_serialNumber(self.as_ptr()); 573 Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null") 574 } 575 } 576 577 to_pem! { 578 /// Serializes the certificate into a PEM-encoded X509 structure. 579 /// 580 /// The output will have a header of `-----BEGIN CERTIFICATE-----`. 581 #[corresponds(PEM_write_bio_X509)] 582 to_pem, 583 ffi::PEM_write_bio_X509 584 } 585 586 to_der! { 587 /// Serializes the certificate into a DER-encoded X509 structure. 588 #[corresponds(i2d_X509)] 589 to_der, 590 ffi::i2d_X509 591 } 592 593 to_pem! { 594 /// Converts the certificate to human readable text. 595 #[corresponds(X509_print)] 596 to_text, 597 ffi::X509_print 598 } 599 } 600 601 impl ToOwned for X509Ref { 602 type Owned = X509; 603 to_owned(&self) -> X509604 fn to_owned(&self) -> X509 { 605 unsafe { 606 X509_up_ref(self.as_ptr()); 607 X509::from_ptr(self.as_ptr()) 608 } 609 } 610 } 611 612 impl Ord for X509Ref { cmp(&self, other: &Self) -> cmp::Ordering613 fn cmp(&self, other: &Self) -> cmp::Ordering { 614 // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than. 615 // It can't fail if both pointers are valid, which we know is true. 616 let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) }; 617 cmp.cmp(&0) 618 } 619 } 620 621 impl PartialOrd for X509Ref { partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>622 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { 623 Some(self.cmp(other)) 624 } 625 } 626 627 impl PartialOrd<X509> for X509Ref { partial_cmp(&self, other: &X509) -> Option<cmp::Ordering>628 fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> { 629 <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other) 630 } 631 } 632 633 impl PartialEq for X509Ref { eq(&self, other: &Self) -> bool634 fn eq(&self, other: &Self) -> bool { 635 self.cmp(other) == cmp::Ordering::Equal 636 } 637 } 638 639 impl PartialEq<X509> for X509Ref { eq(&self, other: &X509) -> bool640 fn eq(&self, other: &X509) -> bool { 641 <X509Ref as PartialEq<X509Ref>>::eq(self, other) 642 } 643 } 644 645 impl Eq for X509Ref {} 646 647 impl X509 { 648 /// Returns a new builder. builder() -> Result<X509Builder, ErrorStack>649 pub fn builder() -> Result<X509Builder, ErrorStack> { 650 X509Builder::new() 651 } 652 653 from_pem! { 654 /// Deserializes a PEM-encoded X509 structure. 655 /// 656 /// The input should have a header of `-----BEGIN CERTIFICATE-----`. 657 #[corresponds(PEM_read_bio_X509)] 658 from_pem, 659 X509, 660 ffi::PEM_read_bio_X509 661 } 662 663 from_der! { 664 /// Deserializes a DER-encoded X509 structure. 665 #[corresponds(d2i_X509)] 666 from_der, 667 X509, 668 ffi::d2i_X509 669 } 670 671 /// Deserializes a list of PEM-formatted certificates. 672 #[corresponds(PEM_read_bio_X509)] stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack>673 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> { 674 unsafe { 675 ffi::init(); 676 let bio = MemBioSlice::new(pem)?; 677 678 let mut certs = vec![]; 679 loop { 680 let r = 681 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()); 682 if r.is_null() { 683 let err = ffi::ERR_peek_last_error(); 684 if ffi::ERR_GET_LIB(err) as X509LenTy == ffi::ERR_LIB_PEM 685 && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE 686 { 687 ffi::ERR_clear_error(); 688 break; 689 } 690 691 return Err(ErrorStack::get()); 692 } else { 693 certs.push(X509(r)); 694 } 695 } 696 697 Ok(certs) 698 } 699 } 700 } 701 702 impl Clone for X509 { clone(&self) -> X509703 fn clone(&self) -> X509 { 704 X509Ref::to_owned(self) 705 } 706 } 707 708 impl fmt::Debug for X509 { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result709 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 710 let serial = match &self.serial_number().to_bn() { 711 Ok(bn) => match bn.to_hex_str() { 712 Ok(hex) => hex.to_string(), 713 Err(_) => "".to_string(), 714 }, 715 Err(_) => "".to_string(), 716 }; 717 let mut debug_struct = formatter.debug_struct("X509"); 718 debug_struct.field("serial_number", &serial); 719 debug_struct.field("signature_algorithm", &self.signature_algorithm().object()); 720 debug_struct.field("issuer", &self.issuer_name()); 721 debug_struct.field("subject", &self.subject_name()); 722 if let Some(subject_alt_names) = &self.subject_alt_names() { 723 debug_struct.field("subject_alt_names", subject_alt_names); 724 } 725 debug_struct.field("not_before", &self.not_before()); 726 debug_struct.field("not_after", &self.not_after()); 727 728 if let Ok(public_key) = &self.public_key() { 729 debug_struct.field("public_key", public_key); 730 }; 731 // TODO: Print extensions once they are supported on the X509 struct. 732 733 debug_struct.finish() 734 } 735 } 736 737 impl AsRef<X509Ref> for X509Ref { as_ref(&self) -> &X509Ref738 fn as_ref(&self) -> &X509Ref { 739 self 740 } 741 } 742 743 impl Stackable for X509 { 744 type StackType = ffi::stack_st_X509; 745 } 746 747 impl Ord for X509 { cmp(&self, other: &Self) -> cmp::Ordering748 fn cmp(&self, other: &Self) -> cmp::Ordering { 749 X509Ref::cmp(self, other) 750 } 751 } 752 753 impl PartialOrd for X509 { partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>754 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { 755 X509Ref::partial_cmp(self, other) 756 } 757 } 758 759 impl PartialOrd<X509Ref> for X509 { partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering>760 fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> { 761 X509Ref::partial_cmp(self, other) 762 } 763 } 764 765 impl PartialEq for X509 { eq(&self, other: &Self) -> bool766 fn eq(&self, other: &Self) -> bool { 767 X509Ref::eq(self, other) 768 } 769 } 770 771 impl PartialEq<X509Ref> for X509 { eq(&self, other: &X509Ref) -> bool772 fn eq(&self, other: &X509Ref) -> bool { 773 X509Ref::eq(self, other) 774 } 775 } 776 777 impl Eq for X509 {} 778 779 /// A context object required to construct certain `X509` extension values. 780 pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>); 781 782 impl<'a> X509v3Context<'a> { as_ptr(&self) -> *mut ffi::X509V3_CTX783 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX { 784 &self.0 as *const _ as *mut _ 785 } 786 } 787 788 foreign_type_and_impl_send_sync! { 789 type CType = ffi::X509_EXTENSION; 790 fn drop = ffi::X509_EXTENSION_free; 791 792 /// Permit additional fields to be added to an `X509` v3 certificate. 793 pub struct X509Extension; 794 /// Reference to `X509Extension`. 795 pub struct X509ExtensionRef; 796 } 797 798 impl Stackable for X509Extension { 799 type StackType = ffi::stack_st_X509_EXTENSION; 800 } 801 802 impl X509Extension { 803 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported 804 /// names and their value formats. 805 /// 806 /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be 807 /// provided. 808 /// 809 /// 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>810 pub fn new( 811 conf: Option<&ConfRef>, 812 context: Option<&X509v3Context<'_>>, 813 name: &str, 814 value: &str, 815 ) -> Result<X509Extension, ErrorStack> { 816 let name = CString::new(name).unwrap(); 817 let value = CString::new(value).unwrap(); 818 unsafe { 819 ffi::init(); 820 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); 821 let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); 822 let name = name.as_ptr() as *mut _; 823 let value = value.as_ptr() as *mut _; 824 825 cvt_p(ffi::X509V3_EXT_nconf(conf, context, name, value)).map(X509Extension) 826 } 827 } 828 829 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported 830 /// extensions and their value formats. 831 /// 832 /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to 833 /// be provided. 834 /// 835 /// 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>836 pub fn new_nid( 837 conf: Option<&ConfRef>, 838 context: Option<&X509v3Context<'_>>, 839 name: Nid, 840 value: &str, 841 ) -> Result<X509Extension, ErrorStack> { 842 let value = CString::new(value).unwrap(); 843 unsafe { 844 ffi::init(); 845 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); 846 let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); 847 let name = name.as_raw(); 848 let value = value.as_ptr() as *mut _; 849 850 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension) 851 } 852 } 853 854 /// Adds an alias for an extension 855 /// 856 /// # Safety 857 /// 858 /// This method modifies global state without locking and therefore is not thread safe 859 #[corresponds(X509V3_EXT_add_alias)] add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack>860 pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> { 861 ffi::init(); 862 cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ()) 863 } 864 } 865 866 /// A builder used to construct an `X509Name`. 867 pub struct X509NameBuilder(X509Name); 868 869 impl X509NameBuilder { 870 /// Creates a new builder. new() -> Result<X509NameBuilder, ErrorStack>871 pub fn new() -> Result<X509NameBuilder, ErrorStack> { 872 unsafe { 873 ffi::init(); 874 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p))) 875 } 876 } 877 878 /// Add a name entry 879 #[corresponds(X509_NAME_add_entry)] 880 #[cfg(any(ossl101, libressl350))] append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack>881 pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> { 882 unsafe { 883 cvt(ffi::X509_NAME_add_entry( 884 self.0.as_ptr(), 885 ne.as_ptr(), 886 -1, 887 0, 888 )) 889 .map(|_| ()) 890 } 891 } 892 893 /// Add a field entry by str. 894 /// 895 /// This corresponds to [`X509_NAME_add_entry_by_txt`]. 896 /// 897 /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack>898 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { 899 unsafe { 900 let field = CString::new(field).unwrap(); 901 assert!(value.len() <= c_int::max_value() as usize); 902 cvt(ffi::X509_NAME_add_entry_by_txt( 903 self.0.as_ptr(), 904 field.as_ptr() as *mut _, 905 ffi::MBSTRING_UTF8, 906 value.as_ptr(), 907 value.len() as c_int, 908 -1, 909 0, 910 )) 911 .map(|_| ()) 912 } 913 } 914 915 /// Add a field entry by str with a specific type. 916 /// 917 /// This corresponds to [`X509_NAME_add_entry_by_txt`]. 918 /// 919 /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html append_entry_by_text_with_type( &mut self, field: &str, value: &str, ty: Asn1Type, ) -> Result<(), ErrorStack>920 pub fn append_entry_by_text_with_type( 921 &mut self, 922 field: &str, 923 value: &str, 924 ty: Asn1Type, 925 ) -> Result<(), ErrorStack> { 926 unsafe { 927 let field = CString::new(field).unwrap(); 928 assert!(value.len() <= c_int::max_value() as usize); 929 cvt(ffi::X509_NAME_add_entry_by_txt( 930 self.0.as_ptr(), 931 field.as_ptr() as *mut _, 932 ty.as_raw(), 933 value.as_ptr(), 934 value.len() as c_int, 935 -1, 936 0, 937 )) 938 .map(|_| ()) 939 } 940 } 941 942 /// Add a field entry by NID. 943 /// 944 /// This corresponds to [`X509_NAME_add_entry_by_NID`]. 945 /// 946 /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack>947 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { 948 unsafe { 949 assert!(value.len() <= c_int::max_value() as usize); 950 cvt(ffi::X509_NAME_add_entry_by_NID( 951 self.0.as_ptr(), 952 field.as_raw(), 953 ffi::MBSTRING_UTF8, 954 value.as_ptr() as *mut _, 955 value.len() as c_int, 956 -1, 957 0, 958 )) 959 .map(|_| ()) 960 } 961 } 962 963 /// Add a field entry by NID with a specific type. 964 /// 965 /// This corresponds to [`X509_NAME_add_entry_by_NID`]. 966 /// 967 /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html append_entry_by_nid_with_type( &mut self, field: Nid, value: &str, ty: Asn1Type, ) -> Result<(), ErrorStack>968 pub fn append_entry_by_nid_with_type( 969 &mut self, 970 field: Nid, 971 value: &str, 972 ty: Asn1Type, 973 ) -> Result<(), ErrorStack> { 974 unsafe { 975 assert!(value.len() <= c_int::max_value() as usize); 976 cvt(ffi::X509_NAME_add_entry_by_NID( 977 self.0.as_ptr(), 978 field.as_raw(), 979 ty.as_raw(), 980 value.as_ptr() as *mut _, 981 value.len() as c_int, 982 -1, 983 0, 984 )) 985 .map(|_| ()) 986 } 987 } 988 989 /// Return an `X509Name`. build(self) -> X509Name990 pub fn build(self) -> X509Name { 991 self.0 992 } 993 } 994 995 foreign_type_and_impl_send_sync! { 996 type CType = ffi::X509_NAME; 997 fn drop = ffi::X509_NAME_free; 998 999 /// The names of an `X509` certificate. 1000 pub struct X509Name; 1001 /// Reference to `X509Name`. 1002 pub struct X509NameRef; 1003 } 1004 1005 impl X509Name { 1006 /// Returns a new builder. builder() -> Result<X509NameBuilder, ErrorStack>1007 pub fn builder() -> Result<X509NameBuilder, ErrorStack> { 1008 X509NameBuilder::new() 1009 } 1010 1011 /// Loads subject names from a file containing PEM-formatted certificates. 1012 /// 1013 /// 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>1014 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> { 1015 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); 1016 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) } 1017 } 1018 1019 from_der! { 1020 /// Deserializes a DER-encoded X509 name structure. 1021 /// 1022 /// This corresponds to [`d2i_X509_NAME`]. 1023 /// 1024 /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html 1025 from_der, 1026 X509Name, 1027 ffi::d2i_X509_NAME 1028 } 1029 } 1030 1031 impl Stackable for X509Name { 1032 type StackType = ffi::stack_st_X509_NAME; 1033 } 1034 1035 impl X509NameRef { 1036 /// Returns the name entries by the nid. entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_>1037 pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> { 1038 X509NameEntries { 1039 name: self, 1040 nid: Some(nid), 1041 loc: -1, 1042 } 1043 } 1044 1045 /// Returns an iterator over all `X509NameEntry` values entries(&self) -> X509NameEntries<'_>1046 pub fn entries(&self) -> X509NameEntries<'_> { 1047 X509NameEntries { 1048 name: self, 1049 nid: None, 1050 loc: -1, 1051 } 1052 } 1053 1054 /// Compare two names, like [`Ord`] but it may fail. 1055 /// 1056 /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp` 1057 /// call fails. 1058 /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may 1059 /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails. 1060 #[corresponds(X509_NAME_cmp)] try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack>1061 pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> { 1062 let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) }; 1063 if cfg!(ossl300) && cmp == -2 { 1064 return Err(ErrorStack::get()); 1065 } 1066 Ok(cmp.cmp(&0)) 1067 } 1068 1069 /// Copies the name to a new `X509Name`. 1070 #[corresponds(X509_NAME_dup)] 1071 #[cfg(any(boringssl, ossl110, libressl270))] to_owned(&self) -> Result<X509Name, ErrorStack>1072 pub fn to_owned(&self) -> Result<X509Name, ErrorStack> { 1073 unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) } 1074 } 1075 1076 to_der! { 1077 /// Serializes the certificate into a DER-encoded X509 name structure. 1078 /// 1079 /// This corresponds to [`i2d_X509_NAME`]. 1080 /// 1081 /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_NAME.html 1082 to_der, 1083 ffi::i2d_X509_NAME 1084 } 1085 } 1086 1087 impl fmt::Debug for X509NameRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1088 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1089 formatter.debug_list().entries(self.entries()).finish() 1090 } 1091 } 1092 1093 /// A type to destructure and examine an `X509Name`. 1094 pub struct X509NameEntries<'a> { 1095 name: &'a X509NameRef, 1096 nid: Option<Nid>, 1097 loc: c_int, 1098 } 1099 1100 impl<'a> Iterator for X509NameEntries<'a> { 1101 type Item = &'a X509NameEntryRef; 1102 next(&mut self) -> Option<&'a X509NameEntryRef>1103 fn next(&mut self) -> Option<&'a X509NameEntryRef> { 1104 unsafe { 1105 match self.nid { 1106 Some(nid) => { 1107 // There is a `Nid` specified to search for 1108 self.loc = 1109 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc); 1110 if self.loc == -1 { 1111 return None; 1112 } 1113 } 1114 None => { 1115 // Iterate over all `Nid`s 1116 self.loc += 1; 1117 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) { 1118 return None; 1119 } 1120 } 1121 } 1122 1123 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); 1124 1125 Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null")) 1126 } 1127 } 1128 } 1129 1130 foreign_type_and_impl_send_sync! { 1131 type CType = ffi::X509_NAME_ENTRY; 1132 fn drop = ffi::X509_NAME_ENTRY_free; 1133 1134 /// A name entry associated with a `X509Name`. 1135 pub struct X509NameEntry; 1136 /// Reference to `X509NameEntry`. 1137 pub struct X509NameEntryRef; 1138 } 1139 1140 impl X509NameEntryRef { 1141 /// Returns the field value of an `X509NameEntry`. 1142 /// 1143 /// This corresponds to [`X509_NAME_ENTRY_get_data`]. 1144 /// 1145 /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_data.html data(&self) -> &Asn1StringRef1146 pub fn data(&self) -> &Asn1StringRef { 1147 unsafe { 1148 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); 1149 Asn1StringRef::from_ptr(data) 1150 } 1151 } 1152 1153 /// Returns the `Asn1Object` value of an `X509NameEntry`. 1154 /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`. 1155 /// 1156 /// This corresponds to [`X509_NAME_ENTRY_get_object`]. 1157 /// 1158 /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_object.html object(&self) -> &Asn1ObjectRef1159 pub fn object(&self) -> &Asn1ObjectRef { 1160 unsafe { 1161 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); 1162 Asn1ObjectRef::from_ptr(object) 1163 } 1164 } 1165 } 1166 1167 impl fmt::Debug for X509NameEntryRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1168 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1169 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data())) 1170 } 1171 } 1172 1173 /// A builder used to construct an `X509Req`. 1174 pub struct X509ReqBuilder(X509Req); 1175 1176 impl X509ReqBuilder { 1177 /// Returns a builder for a certificate request. 1178 /// 1179 /// This corresponds to [`X509_REQ_new`]. 1180 /// 1181 ///[`X509_REQ_new`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_new.html new() -> Result<X509ReqBuilder, ErrorStack>1182 pub fn new() -> Result<X509ReqBuilder, ErrorStack> { 1183 unsafe { 1184 ffi::init(); 1185 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) 1186 } 1187 } 1188 1189 /// Set the numerical value of the version field. 1190 /// 1191 /// This corresponds to [`X509_REQ_set_version`]. 1192 /// 1193 ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_version.html 1194 #[allow(clippy::useless_conversion)] set_version(&mut self, version: i32) -> Result<(), ErrorStack>1195 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { 1196 unsafe { 1197 cvt(ffi::X509_REQ_set_version( 1198 self.0.as_ptr(), 1199 version as c_long, 1200 )) 1201 .map(|_| ()) 1202 } 1203 } 1204 1205 /// Set the issuer name. 1206 /// 1207 /// This corresponds to [`X509_REQ_set_subject_name`]. 1208 /// 1209 /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_subject_name.html set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack>1210 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { 1211 unsafe { 1212 cvt(ffi::X509_REQ_set_subject_name( 1213 self.0.as_ptr(), 1214 subject_name.as_ptr(), 1215 )) 1216 .map(|_| ()) 1217 } 1218 } 1219 1220 /// Set the public key. 1221 /// 1222 /// This corresponds to [`X509_REQ_set_pubkey`]. 1223 /// 1224 /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_pubkey.html set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,1225 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> 1226 where 1227 T: HasPublic, 1228 { 1229 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } 1230 } 1231 1232 /// Return an `X509v3Context`. This context object can be used to construct 1233 /// certain `X509` extensions. x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a>1234 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> { 1235 unsafe { 1236 let mut ctx = mem::zeroed(); 1237 1238 ffi::X509V3_set_ctx( 1239 &mut ctx, 1240 ptr::null_mut(), 1241 ptr::null_mut(), 1242 self.0.as_ptr(), 1243 ptr::null_mut(), 1244 0, 1245 ); 1246 1247 // nodb case taken care of since we zeroed ctx above 1248 if let Some(conf) = conf { 1249 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); 1250 } 1251 1252 X509v3Context(ctx, PhantomData) 1253 } 1254 } 1255 1256 /// Permits any number of extension fields to be added to the certificate. add_extensions( &mut self, extensions: &StackRef<X509Extension>, ) -> Result<(), ErrorStack>1257 pub fn add_extensions( 1258 &mut self, 1259 extensions: &StackRef<X509Extension>, 1260 ) -> Result<(), ErrorStack> { 1261 unsafe { 1262 cvt(ffi::X509_REQ_add_extensions( 1263 self.0.as_ptr(), 1264 extensions.as_ptr(), 1265 )) 1266 .map(|_| ()) 1267 } 1268 } 1269 1270 /// Sign the request using a private key. 1271 /// 1272 /// This corresponds to [`X509_REQ_sign`]. 1273 /// 1274 /// [`X509_REQ_sign`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_sign.html sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate,1275 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> 1276 where 1277 T: HasPrivate, 1278 { 1279 unsafe { 1280 cvt(ffi::X509_REQ_sign( 1281 self.0.as_ptr(), 1282 key.as_ptr(), 1283 hash.as_ptr(), 1284 )) 1285 .map(|_| ()) 1286 } 1287 } 1288 1289 /// Returns the `X509Req`. build(self) -> X509Req1290 pub fn build(self) -> X509Req { 1291 self.0 1292 } 1293 } 1294 1295 foreign_type_and_impl_send_sync! { 1296 type CType = ffi::X509_REQ; 1297 fn drop = ffi::X509_REQ_free; 1298 1299 /// An `X509` certificate request. 1300 pub struct X509Req; 1301 /// Reference to `X509Req`. 1302 pub struct X509ReqRef; 1303 } 1304 1305 impl X509Req { 1306 /// A builder for `X509Req`. builder() -> Result<X509ReqBuilder, ErrorStack>1307 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> { 1308 X509ReqBuilder::new() 1309 } 1310 1311 from_pem! { 1312 /// Deserializes a PEM-encoded PKCS#10 certificate request structure. 1313 /// 1314 /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`. 1315 /// 1316 /// This corresponds to [`PEM_read_bio_X509_REQ`]. 1317 /// 1318 /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_read_bio_X509_REQ.html 1319 from_pem, 1320 X509Req, 1321 ffi::PEM_read_bio_X509_REQ 1322 } 1323 1324 from_der! { 1325 /// Deserializes a DER-encoded PKCS#10 certificate request structure. 1326 /// 1327 /// This corresponds to [`d2i_X509_REQ`]. 1328 /// 1329 /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/d2i_X509_REQ.html 1330 from_der, 1331 X509Req, 1332 ffi::d2i_X509_REQ 1333 } 1334 } 1335 1336 impl X509ReqRef { 1337 to_pem! { 1338 /// Serializes the certificate request to a PEM-encoded PKCS#10 structure. 1339 /// 1340 /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`. 1341 /// 1342 /// This corresponds to [`PEM_write_bio_X509_REQ`]. 1343 /// 1344 /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_write_bio_X509_REQ.html 1345 to_pem, 1346 ffi::PEM_write_bio_X509_REQ 1347 } 1348 1349 to_der! { 1350 /// Serializes the certificate request to a DER-encoded PKCS#10 structure. 1351 /// 1352 /// This corresponds to [`i2d_X509_REQ`]. 1353 /// 1354 /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_REQ.html 1355 to_der, 1356 ffi::i2d_X509_REQ 1357 } 1358 1359 to_pem! { 1360 /// Converts the request to human readable text. 1361 #[corresponds(X509_Req_print)] 1362 to_text, 1363 ffi::X509_REQ_print 1364 } 1365 1366 /// Returns the numerical value of the version field of the certificate request. 1367 /// 1368 /// This corresponds to [`X509_REQ_get_version`] 1369 /// 1370 /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html version(&self) -> i321371 pub fn version(&self) -> i32 { 1372 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } 1373 } 1374 1375 /// Returns the subject name of the certificate request. 1376 /// 1377 /// This corresponds to [`X509_REQ_get_subject_name`] 1378 /// 1379 /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_subject_name.html subject_name(&self) -> &X509NameRef1380 pub fn subject_name(&self) -> &X509NameRef { 1381 unsafe { 1382 let name = X509_REQ_get_subject_name(self.as_ptr()); 1383 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") 1384 } 1385 } 1386 1387 /// Returns the public key of the certificate request. 1388 /// 1389 /// This corresponds to [`X509_REQ_get_pubkey"] 1390 /// 1391 /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_pubkey.html public_key(&self) -> Result<PKey<Public>, ErrorStack>1392 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> { 1393 unsafe { 1394 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?; 1395 Ok(PKey::from_ptr(key)) 1396 } 1397 } 1398 1399 /// Check if the certificate request is signed using the given public key. 1400 /// 1401 /// Returns `true` if verification succeeds. 1402 /// 1403 /// This corresponds to [`X509_REQ_verify"]. 1404 /// 1405 /// [`X509_REQ_verify`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_verify.html verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,1406 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 1407 where 1408 T: HasPublic, 1409 { 1410 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 1411 } 1412 1413 /// Returns the extensions of the certificate request. 1414 /// 1415 /// This corresponds to [`X509_REQ_get_extensions"] extensions(&self) -> Result<Stack<X509Extension>, ErrorStack>1416 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> { 1417 unsafe { 1418 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?; 1419 Ok(Stack::from_ptr(extensions)) 1420 } 1421 } 1422 } 1423 1424 foreign_type_and_impl_send_sync! { 1425 type CType = ffi::X509_REVOKED; 1426 fn drop = ffi::X509_REVOKED_free; 1427 1428 /// An `X509` certificate request. 1429 pub struct X509Revoked; 1430 /// Reference to `X509Crl`. 1431 pub struct X509RevokedRef; 1432 } 1433 1434 impl Stackable for X509Revoked { 1435 type StackType = ffi::stack_st_X509_REVOKED; 1436 } 1437 1438 impl X509Revoked { 1439 from_der! { 1440 /// Deserializes a DER-encoded certificate revocation status 1441 #[corresponds(d2i_X509_REVOKED)] 1442 from_der, 1443 X509Revoked, 1444 ffi::d2i_X509_REVOKED 1445 } 1446 } 1447 1448 impl X509RevokedRef { 1449 to_der! { 1450 /// Serializes the certificate request to a DER-encoded certificate revocation status 1451 #[corresponds(d2i_X509_REVOKED)] 1452 to_der, 1453 ffi::i2d_X509_REVOKED 1454 } 1455 1456 /// Get the date that the certificate was revoked 1457 #[corresponds(X509_REVOKED_get0_revocationDate)] revocation_date(&self) -> &Asn1TimeRef1458 pub fn revocation_date(&self) -> &Asn1TimeRef { 1459 unsafe { 1460 let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _); 1461 assert!(!r.is_null()); 1462 Asn1TimeRef::from_ptr(r as *mut _) 1463 } 1464 } 1465 1466 /// Get the serial number of the revoked certificate 1467 #[corresponds(X509_REVOKED_get0_serialNumber)] serial_number(&self) -> &Asn1IntegerRef1468 pub fn serial_number(&self) -> &Asn1IntegerRef { 1469 unsafe { 1470 let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _); 1471 assert!(!r.is_null()); 1472 Asn1IntegerRef::from_ptr(r as *mut _) 1473 } 1474 } 1475 } 1476 1477 foreign_type_and_impl_send_sync! { 1478 type CType = ffi::X509_CRL; 1479 fn drop = ffi::X509_CRL_free; 1480 1481 /// An `X509` certificate request. 1482 pub struct X509Crl; 1483 /// Reference to `X509Crl`. 1484 pub struct X509CrlRef; 1485 } 1486 1487 /// The status of a certificate in a revoction list 1488 /// 1489 /// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods. 1490 /// 1491 /// [`X509_CRL_get0_by_*`]: https://www.openssl.org/docs/man1.1.0/man3/X509_CRL_get0_by_serial.html 1492 pub enum CrlStatus<'a> { 1493 /// The certificate is not present in the list 1494 NotRevoked, 1495 /// The certificate is in the list and is revoked 1496 Revoked(&'a X509RevokedRef), 1497 /// The certificate is in the list, but has the "removeFromCrl" status. 1498 /// 1499 /// This can occur if the certificate was revoked with the "CertificateHold" 1500 /// reason, and has since been unrevoked. 1501 RemoveFromCrl(&'a X509RevokedRef), 1502 } 1503 1504 impl<'a> CrlStatus<'a> { 1505 // Helper used by the X509_CRL_get0_by_* methods to convert their return 1506 // value to the status enum. 1507 // Safety note: the returned CrlStatus must not outlive the owner of the 1508 // revoked_entry pointer. from_ffi_status( status: c_int, revoked_entry: *mut ffi::X509_REVOKED, ) -> CrlStatus<'a>1509 unsafe fn from_ffi_status( 1510 status: c_int, 1511 revoked_entry: *mut ffi::X509_REVOKED, 1512 ) -> CrlStatus<'a> { 1513 match status { 1514 0 => CrlStatus::NotRevoked, 1515 1 => { 1516 assert!(!revoked_entry.is_null()); 1517 CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry)) 1518 } 1519 2 => { 1520 assert!(!revoked_entry.is_null()); 1521 CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry)) 1522 } 1523 _ => unreachable!( 1524 "{}", 1525 "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2." 1526 ), 1527 } 1528 } 1529 } 1530 1531 impl X509Crl { 1532 from_pem! { 1533 /// Deserializes a PEM-encoded Certificate Revocation List 1534 /// 1535 /// The input should have a header of `-----BEGIN X509 CRL-----`. 1536 #[corresponds(PEM_read_bio_X509_CRL)] 1537 from_pem, 1538 X509Crl, 1539 ffi::PEM_read_bio_X509_CRL 1540 } 1541 1542 from_der! { 1543 /// Deserializes a DER-encoded Certificate Revocation List 1544 #[corresponds(d2i_X509_CRL)] 1545 from_der, 1546 X509Crl, 1547 ffi::d2i_X509_CRL 1548 } 1549 } 1550 1551 impl X509CrlRef { 1552 to_pem! { 1553 /// Serializes the certificate request to a PEM-encoded Certificate Revocation List. 1554 /// 1555 /// The output will have a header of `-----BEGIN X509 CRL-----`. 1556 #[corresponds(PEM_write_bio_X509_CRL)] 1557 to_pem, 1558 ffi::PEM_write_bio_X509_CRL 1559 } 1560 1561 to_der! { 1562 /// Serializes the certificate request to a DER-encoded Certificate Revocation List. 1563 #[corresponds(i2d_X509_CRL)] 1564 to_der, 1565 ffi::i2d_X509_CRL 1566 } 1567 1568 /// Get the stack of revocation entries get_revoked(&self) -> Option<&StackRef<X509Revoked>>1569 pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> { 1570 unsafe { 1571 let revoked = X509_CRL_get_REVOKED(self.as_ptr()); 1572 if revoked.is_null() { 1573 None 1574 } else { 1575 Some(StackRef::from_ptr(revoked)) 1576 } 1577 } 1578 } 1579 1580 /// Returns the CRL's `lastUpdate` time. 1581 #[corresponds(X509_CRL_get0_lastUpdate)] last_update(&self) -> &Asn1TimeRef1582 pub fn last_update(&self) -> &Asn1TimeRef { 1583 unsafe { 1584 let date = X509_CRL_get0_lastUpdate(self.as_ptr()); 1585 assert!(!date.is_null()); 1586 Asn1TimeRef::from_ptr(date as *mut _) 1587 } 1588 } 1589 1590 /// Returns the CRL's `nextUpdate` time. 1591 /// 1592 /// If the `nextUpdate` field is missing, returns `None`. 1593 #[corresponds(X509_CRL_get0_nextUpdate)] next_update(&self) -> Option<&Asn1TimeRef>1594 pub fn next_update(&self) -> Option<&Asn1TimeRef> { 1595 unsafe { 1596 let date = X509_CRL_get0_nextUpdate(self.as_ptr()); 1597 Asn1TimeRef::from_const_ptr_opt(date) 1598 } 1599 } 1600 1601 /// Get the revocation status of a certificate by its serial number 1602 #[corresponds(X509_CRL_get0_by_serial)] get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a>1603 pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> { 1604 unsafe { 1605 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>(); 1606 let status = 1607 ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr()); 1608 CrlStatus::from_ffi_status(status, ret) 1609 } 1610 } 1611 1612 /// Get the revocation status of a certificate 1613 #[corresponds(X509_CRL_get0_by_cert)] get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a>1614 pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> { 1615 unsafe { 1616 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>(); 1617 let status = 1618 ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr()); 1619 CrlStatus::from_ffi_status(status, ret) 1620 } 1621 } 1622 1623 /// Get the issuer name from the revocation list. 1624 #[corresponds(X509_CRL_get_issuer)] issuer_name(&self) -> &X509NameRef1625 pub fn issuer_name(&self) -> &X509NameRef { 1626 unsafe { 1627 let name = X509_CRL_get_issuer(self.as_ptr()); 1628 assert!(!name.is_null()); 1629 X509NameRef::from_ptr(name) 1630 } 1631 } 1632 1633 /// Check if the CRL is signed using the given public key. 1634 /// 1635 /// Only the signature is checked: no other checks (such as certificate chain validity) 1636 /// are performed. 1637 /// 1638 /// Returns `true` if verification succeeds. 1639 #[corresponds(X509_CRL_verify)] verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,1640 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 1641 where 1642 T: HasPublic, 1643 { 1644 unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 1645 } 1646 } 1647 1648 /// The result of peer certificate verification. 1649 #[derive(Copy, Clone, PartialEq, Eq)] 1650 pub struct X509VerifyResult(c_int); 1651 1652 impl fmt::Debug for X509VerifyResult { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1653 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 1654 fmt.debug_struct("X509VerifyResult") 1655 .field("code", &self.0) 1656 .field("error", &self.error_string()) 1657 .finish() 1658 } 1659 } 1660 1661 impl fmt::Display for X509VerifyResult { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1662 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 1663 fmt.write_str(self.error_string()) 1664 } 1665 } 1666 1667 impl Error for X509VerifyResult {} 1668 1669 impl X509VerifyResult { 1670 /// Creates an `X509VerifyResult` from a raw error number. 1671 /// 1672 /// # Safety 1673 /// 1674 /// Some methods on `X509VerifyResult` are not thread safe if the error 1675 /// number is invalid. from_raw(err: c_int) -> X509VerifyResult1676 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult { 1677 X509VerifyResult(err) 1678 } 1679 1680 /// Return the integer representation of an `X509VerifyResult`. 1681 #[allow(clippy::trivially_copy_pass_by_ref)] as_raw(&self) -> c_int1682 pub fn as_raw(&self) -> c_int { 1683 self.0 1684 } 1685 1686 /// Return a human readable error string from the verification error. 1687 /// 1688 /// This corresponds to [`X509_verify_cert_error_string`]. 1689 /// 1690 /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/manmaster/crypto/X509_verify_cert_error_string.html 1691 #[allow(clippy::trivially_copy_pass_by_ref)] error_string(&self) -> &'static str1692 pub fn error_string(&self) -> &'static str { 1693 ffi::init(); 1694 1695 unsafe { 1696 let s = ffi::X509_verify_cert_error_string(self.0 as c_long); 1697 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() 1698 } 1699 } 1700 1701 /// Successful peer certificate verification. 1702 pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK); 1703 /// Application verification failure. 1704 pub const APPLICATION_VERIFICATION: X509VerifyResult = 1705 X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION); 1706 } 1707 1708 foreign_type_and_impl_send_sync! { 1709 type CType = ffi::GENERAL_NAME; 1710 fn drop = ffi::GENERAL_NAME_free; 1711 1712 /// An `X509` certificate alternative names. 1713 pub struct GeneralName; 1714 /// Reference to `GeneralName`. 1715 pub struct GeneralNameRef; 1716 } 1717 1718 impl GeneralNameRef { ia5_string(&self, ffi_type: c_int) -> Option<&str>1719 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { 1720 unsafe { 1721 if (*self.as_ptr()).type_ != ffi_type { 1722 return None; 1723 } 1724 1725 #[cfg(boringssl)] 1726 let d = (*self.as_ptr()).d.ptr; 1727 #[cfg(not(boringssl))] 1728 let d = (*self.as_ptr()).d; 1729 1730 let ptr = ASN1_STRING_get0_data(d as *mut _); 1731 let len = ffi::ASN1_STRING_length(d as *mut _); 1732 1733 let slice = slice::from_raw_parts(ptr as *const u8, len as usize); 1734 // IA5Strings are stated to be ASCII (specifically IA5). Hopefully 1735 // OpenSSL checks that when loading a certificate but if not we'll 1736 // use this instead of from_utf8_unchecked just in case. 1737 str::from_utf8(slice).ok() 1738 } 1739 } 1740 1741 /// Returns the contents of this `GeneralName` if it is an `rfc822Name`. email(&self) -> Option<&str>1742 pub fn email(&self) -> Option<&str> { 1743 self.ia5_string(ffi::GEN_EMAIL) 1744 } 1745 1746 /// Returns the contents of this `GeneralName` if it is a `dNSName`. dnsname(&self) -> Option<&str>1747 pub fn dnsname(&self) -> Option<&str> { 1748 self.ia5_string(ffi::GEN_DNS) 1749 } 1750 1751 /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`. uri(&self) -> Option<&str>1752 pub fn uri(&self) -> Option<&str> { 1753 self.ia5_string(ffi::GEN_URI) 1754 } 1755 1756 /// Returns the contents of this `GeneralName` if it is an `iPAddress`. ipaddress(&self) -> Option<&[u8]>1757 pub fn ipaddress(&self) -> Option<&[u8]> { 1758 unsafe { 1759 if (*self.as_ptr()).type_ != ffi::GEN_IPADD { 1760 return None; 1761 } 1762 #[cfg(boringssl)] 1763 let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d); 1764 #[cfg(not(boringssl))] 1765 let d = (*self.as_ptr()).d; 1766 1767 let ptr = ASN1_STRING_get0_data(d as *mut _); 1768 let len = ffi::ASN1_STRING_length(d as *mut _); 1769 1770 Some(slice::from_raw_parts(ptr as *const u8, len as usize)) 1771 } 1772 } 1773 } 1774 1775 impl fmt::Debug for GeneralNameRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1776 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1777 if let Some(email) = self.email() { 1778 formatter.write_str(email) 1779 } else if let Some(dnsname) = self.dnsname() { 1780 formatter.write_str(dnsname) 1781 } else if let Some(uri) = self.uri() { 1782 formatter.write_str(uri) 1783 } else if let Some(ipaddress) = self.ipaddress() { 1784 let address = <[u8; 16]>::try_from(ipaddress) 1785 .map(IpAddr::from) 1786 .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from)); 1787 match address { 1788 Ok(a) => fmt::Debug::fmt(&a, formatter), 1789 Err(_) => fmt::Debug::fmt(ipaddress, formatter), 1790 } 1791 } else { 1792 formatter.write_str("(empty)") 1793 } 1794 } 1795 } 1796 1797 impl Stackable for GeneralName { 1798 type StackType = ffi::stack_st_GENERAL_NAME; 1799 } 1800 1801 foreign_type_and_impl_send_sync! { 1802 type CType = ffi::ACCESS_DESCRIPTION; 1803 fn drop = ffi::ACCESS_DESCRIPTION_free; 1804 1805 /// `AccessDescription` of certificate authority information. 1806 pub struct AccessDescription; 1807 /// Reference to `AccessDescription`. 1808 pub struct AccessDescriptionRef; 1809 } 1810 1811 impl AccessDescriptionRef { 1812 /// Returns the access method OID. method(&self) -> &Asn1ObjectRef1813 pub fn method(&self) -> &Asn1ObjectRef { 1814 unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) } 1815 } 1816 1817 // Returns the access location. location(&self) -> &GeneralNameRef1818 pub fn location(&self) -> &GeneralNameRef { 1819 unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) } 1820 } 1821 } 1822 1823 impl Stackable for AccessDescription { 1824 type StackType = ffi::stack_st_ACCESS_DESCRIPTION; 1825 } 1826 1827 foreign_type_and_impl_send_sync! { 1828 type CType = ffi::X509_ALGOR; 1829 fn drop = ffi::X509_ALGOR_free; 1830 1831 /// An `X509` certificate signature algorithm. 1832 pub struct X509Algorithm; 1833 /// Reference to `X509Algorithm`. 1834 pub struct X509AlgorithmRef; 1835 } 1836 1837 impl X509AlgorithmRef { 1838 /// Returns the ASN.1 OID of this algorithm. object(&self) -> &Asn1ObjectRef1839 pub fn object(&self) -> &Asn1ObjectRef { 1840 unsafe { 1841 let mut oid = ptr::null(); 1842 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); 1843 Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null") 1844 } 1845 } 1846 } 1847 1848 foreign_type_and_impl_send_sync! { 1849 type CType = ffi::X509_OBJECT; 1850 fn drop = X509_OBJECT_free; 1851 1852 /// An `X509` or an X509 certificate revocation list. 1853 pub struct X509Object; 1854 /// Reference to `X509Object` 1855 pub struct X509ObjectRef; 1856 } 1857 1858 impl X509ObjectRef { x509(&self) -> Option<&X509Ref>1859 pub fn x509(&self) -> Option<&X509Ref> { 1860 unsafe { 1861 let ptr = X509_OBJECT_get0_X509(self.as_ptr()); 1862 X509Ref::from_const_ptr_opt(ptr) 1863 } 1864 } 1865 } 1866 1867 impl Stackable for X509Object { 1868 type StackType = ffi::stack_st_X509_OBJECT; 1869 } 1870 1871 cfg_if! { 1872 if #[cfg(any(boringssl, ossl110, libressl273))] { 1873 use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature}; 1874 } else { 1875 #[allow(bad_style)] 1876 unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { 1877 (*(*(*x).cert_info).validity).notAfter 1878 } 1879 1880 #[allow(bad_style)] 1881 unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { 1882 (*(*(*x).cert_info).validity).notBefore 1883 } 1884 1885 #[allow(bad_style)] 1886 unsafe fn X509_up_ref(x: *mut ffi::X509) { 1887 ffi::CRYPTO_add_lock( 1888 &mut (*x).references, 1889 1, 1890 ffi::CRYPTO_LOCK_X509, 1891 "mod.rs\0".as_ptr() as *const _, 1892 line!() as c_int, 1893 ); 1894 } 1895 1896 #[allow(bad_style)] 1897 unsafe fn X509_get0_signature( 1898 psig: *mut *const ffi::ASN1_BIT_STRING, 1899 palg: *mut *const ffi::X509_ALGOR, 1900 x: *const ffi::X509, 1901 ) { 1902 if !psig.is_null() { 1903 *psig = (*x).signature; 1904 } 1905 if !palg.is_null() { 1906 *palg = (*x).sig_alg; 1907 } 1908 } 1909 } 1910 } 1911 1912 cfg_if! { 1913 if #[cfg(any(boringssl, ossl110, libressl350))] { 1914 use ffi::{ 1915 X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter, 1916 X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name, 1917 }; 1918 } else { 1919 use ffi::{ 1920 ASN1_STRING_data as ASN1_STRING_get0_data, 1921 X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, 1922 X509_set_notAfter as X509_set1_notAfter, 1923 X509_set_notBefore as X509_set1_notBefore, 1924 }; 1925 1926 #[allow(bad_style)] 1927 unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { 1928 ffi::ASN1_INTEGER_get((*(*x).req_info).version) 1929 } 1930 1931 #[allow(bad_style)] 1932 unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { 1933 (*(*x).req_info).subject 1934 } 1935 1936 #[allow(bad_style)] 1937 unsafe fn X509_ALGOR_get0( 1938 paobj: *mut *const ffi::ASN1_OBJECT, 1939 pptype: *mut c_int, 1940 pval: *mut *mut ::libc::c_void, 1941 alg: *const ffi::X509_ALGOR, 1942 ) { 1943 if !paobj.is_null() { 1944 *paobj = (*alg).algorithm; 1945 } 1946 assert!(pptype.is_null()); 1947 assert!(pval.is_null()); 1948 } 1949 } 1950 } 1951 1952 cfg_if! { 1953 if #[cfg(any(ossl110, boringssl, libressl270))] { 1954 use ffi::X509_OBJECT_get0_X509; 1955 } else { 1956 #[allow(bad_style)] 1957 unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 { 1958 if (*x).type_ == ffi::X509_LU_X509 { 1959 (*x).data.x509 1960 } else { 1961 ptr::null_mut() 1962 } 1963 } 1964 } 1965 } 1966 1967 cfg_if! { 1968 if #[cfg(any(ossl110, libressl350))] { 1969 use ffi::X509_OBJECT_free; 1970 } else if #[cfg(boringssl)] { 1971 use ffi::X509_OBJECT_free_contents as X509_OBJECT_free; 1972 } else { 1973 #[allow(bad_style)] 1974 unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) { 1975 ffi::X509_OBJECT_free_contents(x); 1976 ffi::CRYPTO_free(x as *mut libc::c_void); 1977 } 1978 } 1979 } 1980 1981 cfg_if! { 1982 if #[cfg(any(ossl110, libressl350, boringssl))] { 1983 use ffi::{ 1984 X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate, 1985 X509_CRL_get_REVOKED, 1986 X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber, 1987 }; 1988 } else { 1989 #[allow(bad_style)] 1990 unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { 1991 (*(*x).crl).lastUpdate 1992 } 1993 #[allow(bad_style)] 1994 unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { 1995 (*(*x).crl).nextUpdate 1996 } 1997 #[allow(bad_style)] 1998 unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME { 1999 (*(*x).crl).issuer 2000 } 2001 #[allow(bad_style)] 2002 unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED { 2003 (*(*x).crl).revoked 2004 } 2005 #[allow(bad_style)] 2006 unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER { 2007 (*x).serialNumber 2008 } 2009 #[allow(bad_style)] 2010 unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME { 2011 (*x).revocationDate 2012 } 2013 } 2014 } 2015 2016 #[derive(Copy, Clone, PartialEq, Eq)] 2017 pub struct X509PurposeId(c_int); 2018 2019 impl X509PurposeId { 2020 pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT); 2021 pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER); 2022 pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER); 2023 pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN); 2024 pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT); 2025 pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN); 2026 pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY); 2027 pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER); 2028 pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN); 2029 2030 /// Constructs an `X509PurposeId` from a raw OpenSSL value. from_raw(id: c_int) -> Self2031 pub fn from_raw(id: c_int) -> Self { 2032 X509PurposeId(id) 2033 } 2034 2035 /// Returns the raw OpenSSL value represented by this type. as_raw(&self) -> c_int2036 pub fn as_raw(&self) -> c_int { 2037 self.0 2038 } 2039 } 2040 2041 /// A reference to an [`X509_PURPOSE`]. 2042 pub struct X509PurposeRef(Opaque); 2043 2044 /// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL. 2045 impl ForeignTypeRef for X509PurposeRef { 2046 type CType = ffi::X509_PURPOSE; 2047 } 2048 2049 impl X509PurposeRef { 2050 /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short 2051 /// names include 2052 /// - "sslclient", 2053 /// - "sslserver", 2054 /// - "nssslserver", 2055 /// - "smimesign", 2056 /// - "smimeencrypt", 2057 /// - "crlsign", 2058 /// - "any", 2059 /// - "ocsphelper", 2060 /// - "timestampsign" 2061 /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose. 2062 #[allow(clippy::unnecessary_cast)] get_by_sname(sname: &str) -> Result<c_int, ErrorStack>2063 pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> { 2064 unsafe { 2065 let sname = CString::new(sname).unwrap(); 2066 cfg_if! { 2067 if #[cfg(any(ossl110, libressl280))] { 2068 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?; 2069 } else { 2070 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?; 2071 } 2072 } 2073 Ok(purpose) 2074 } 2075 } 2076 /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g. 2077 /// `X509PurposeRef::get_by_sname()`. 2078 #[corresponds(X509_PURPOSE_get0)] from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack>2079 pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> { 2080 unsafe { 2081 let ptr = cvt_p(ffi::X509_PURPOSE_get0(idx))?; 2082 Ok(X509PurposeRef::from_ptr(ptr)) 2083 } 2084 } 2085 2086 /// Get the purpose value from an X509Purpose structure. This value is one of 2087 /// - `X509_PURPOSE_SSL_CLIENT` 2088 /// - `X509_PURPOSE_SSL_SERVER` 2089 /// - `X509_PURPOSE_NS_SSL_SERVER` 2090 /// - `X509_PURPOSE_SMIME_SIGN` 2091 /// - `X509_PURPOSE_SMIME_ENCRYPT` 2092 /// - `X509_PURPOSE_CRL_SIGN` 2093 /// - `X509_PURPOSE_ANY` 2094 /// - `X509_PURPOSE_OCSP_HELPER` 2095 /// - `X509_PURPOSE_TIMESTAMP_SIGN` purpose(&self) -> X509PurposeId2096 pub fn purpose(&self) -> X509PurposeId { 2097 unsafe { 2098 let x509_purpose: *mut ffi::X509_PURPOSE = self.as_ptr(); 2099 X509PurposeId::from_raw((*x509_purpose).purpose) 2100 } 2101 } 2102 } 2103