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, c_void}; 13 use std::cmp::{self, Ordering}; 14 use std::convert::{TryFrom, TryInto}; 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, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, 28 Asn1OctetStringRef, Asn1StringRef, Asn1TimeRef, Asn1Type, 29 }; 30 use crate::bio::MemBioSlice; 31 use crate::conf::ConfRef; 32 use crate::error::ErrorStack; 33 use crate::ex_data::Index; 34 use crate::hash::{DigestBytes, MessageDigest}; 35 use crate::nid::Nid; 36 use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; 37 use crate::ssl::SslRef; 38 use crate::stack::{Stack, StackRef, Stackable}; 39 use crate::string::OpensslString; 40 use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; 41 use crate::{cvt, cvt_n, cvt_p}; 42 use openssl_macros::corresponds; 43 44 #[cfg(any(ossl102, libressl261))] 45 pub mod verify; 46 47 pub mod extension; 48 pub mod store; 49 50 #[cfg(test)] 51 mod tests; 52 53 /// A type of X509 extension. 54 /// 55 /// # Safety 56 /// The value of NID and Output must match those in OpenSSL so that 57 /// `Output::from_ptr_opt(*_get_ext_d2i(*, NID, ...))` is valid. 58 pub unsafe trait ExtensionType { 59 const NID: Nid; 60 type Output: ForeignType; 61 } 62 63 foreign_type_and_impl_send_sync! { 64 type CType = ffi::X509_STORE_CTX; 65 fn drop = ffi::X509_STORE_CTX_free; 66 67 /// An `X509` certificate store context. 68 pub struct X509StoreContext; 69 70 /// A reference to an [`X509StoreContext`]. 71 pub struct X509StoreContextRef; 72 } 73 74 impl X509StoreContext { 75 /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a 76 /// context. 77 #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)] ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack>78 pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> { 79 unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) } 80 } 81 82 /// Creates a new `X509StoreContext` instance. 83 #[corresponds(X509_STORE_CTX_new)] new() -> Result<X509StoreContext, ErrorStack>84 pub fn new() -> Result<X509StoreContext, ErrorStack> { 85 unsafe { 86 ffi::init(); 87 cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext) 88 } 89 } 90 } 91 92 impl X509StoreContextRef { 93 /// Returns application data pertaining to an `X509` store context. 94 #[corresponds(X509_STORE_CTX_get_ex_data)] ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T>95 pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> { 96 unsafe { 97 let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw()); 98 if data.is_null() { 99 None 100 } else { 101 Some(&*(data as *const T)) 102 } 103 } 104 } 105 106 /// Returns the error code of the context. 107 #[corresponds(X509_STORE_CTX_get_error)] error(&self) -> X509VerifyResult108 pub fn error(&self) -> X509VerifyResult { 109 unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) } 110 } 111 112 /// Initializes this context with the given certificate, certificates chain and certificate 113 /// store. After initializing the context, the `with_context` closure is called with the prepared 114 /// context. As long as the closure is running, the context stays initialized and can be used 115 /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished. 116 /// 117 /// * `trust` - The certificate store with the trusted certificates. 118 /// * `cert` - The certificate that should be verified. 119 /// * `cert_chain` - The certificates chain. 120 /// * `with_context` - The closure that is called with the initialized context. 121 /// 122 /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to 123 /// [`X509_STORE_CTX_cleanup`] after calling `with_context`. 124 /// 125 /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_init.html 126 /// [`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>,127 pub fn init<F, T>( 128 &mut self, 129 trust: &store::X509StoreRef, 130 cert: &X509Ref, 131 cert_chain: &StackRef<X509>, 132 with_context: F, 133 ) -> Result<T, ErrorStack> 134 where 135 F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>, 136 { 137 struct Cleanup<'a>(&'a mut X509StoreContextRef); 138 139 impl<'a> Drop for Cleanup<'a> { 140 fn drop(&mut self) { 141 unsafe { 142 ffi::X509_STORE_CTX_cleanup(self.0.as_ptr()); 143 } 144 } 145 } 146 147 unsafe { 148 cvt(ffi::X509_STORE_CTX_init( 149 self.as_ptr(), 150 trust.as_ptr(), 151 cert.as_ptr(), 152 cert_chain.as_ptr(), 153 ))?; 154 155 let cleanup = Cleanup(self); 156 with_context(cleanup.0) 157 } 158 } 159 160 /// Verifies the stored certificate. 161 /// 162 /// Returns `true` if verification succeeds. The `error` method will return the specific 163 /// validation error if the certificate was not valid. 164 /// 165 /// This will only work inside of a call to `init`. 166 #[corresponds(X509_verify_cert)] verify_cert(&mut self) -> Result<bool, ErrorStack>167 pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> { 168 unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) } 169 } 170 171 /// Set the error code of the context. 172 #[corresponds(X509_STORE_CTX_set_error)] set_error(&mut self, result: X509VerifyResult)173 pub fn set_error(&mut self, result: X509VerifyResult) { 174 unsafe { 175 ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw()); 176 } 177 } 178 179 /// Returns a reference to the certificate which caused the error or None if 180 /// no certificate is relevant to the error. 181 #[corresponds(X509_STORE_CTX_get_current_cert)] current_cert(&self) -> Option<&X509Ref>182 pub fn current_cert(&self) -> Option<&X509Ref> { 183 unsafe { 184 let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr()); 185 X509Ref::from_const_ptr_opt(ptr) 186 } 187 } 188 189 /// Returns a non-negative integer representing the depth in the certificate 190 /// chain where the error occurred. If it is zero it occurred in the end 191 /// entity certificate, one if it is the certificate which signed the end 192 /// entity certificate and so on. 193 #[corresponds(X509_STORE_CTX_get_error_depth)] error_depth(&self) -> u32194 pub fn error_depth(&self) -> u32 { 195 unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 } 196 } 197 198 /// Returns a reference to a complete valid `X509` certificate chain. 199 #[corresponds(X509_STORE_CTX_get0_chain)] chain(&self) -> Option<&StackRef<X509>>200 pub fn chain(&self) -> Option<&StackRef<X509>> { 201 unsafe { 202 let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); 203 204 if chain.is_null() { 205 None 206 } else { 207 Some(StackRef::from_ptr(chain)) 208 } 209 } 210 } 211 } 212 213 /// A builder used to construct an `X509`. 214 pub struct X509Builder(X509); 215 216 impl X509Builder { 217 /// Creates a new builder. 218 #[corresponds(X509_new)] new() -> Result<X509Builder, ErrorStack>219 pub fn new() -> Result<X509Builder, ErrorStack> { 220 unsafe { 221 ffi::init(); 222 cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p))) 223 } 224 } 225 226 /// Sets the notAfter constraint on the certificate. 227 #[corresponds(X509_set1_notAfter)] set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack>228 pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { 229 unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } 230 } 231 232 /// Sets the notBefore constraint on the certificate. 233 #[corresponds(X509_set1_notBefore)] set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack>234 pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { 235 unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } 236 } 237 238 /// Sets the version of the certificate. 239 /// 240 /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of 241 /// the X.509 standard should pass `2` to this method. 242 #[corresponds(X509_set_version)] 243 #[allow(clippy::useless_conversion)] set_version(&mut self, version: i32) -> Result<(), ErrorStack>244 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { 245 unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) } 246 } 247 248 /// Sets the serial number of the certificate. 249 #[corresponds(X509_set_serialNumber)] set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack>250 pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> { 251 unsafe { 252 cvt(ffi::X509_set_serialNumber( 253 self.0.as_ptr(), 254 serial_number.as_ptr(), 255 )) 256 .map(|_| ()) 257 } 258 } 259 260 /// Sets the issuer name of the certificate. 261 #[corresponds(X509_set_issuer_name)] set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack>262 pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> { 263 unsafe { 264 cvt(ffi::X509_set_issuer_name( 265 self.0.as_ptr(), 266 issuer_name.as_ptr(), 267 )) 268 .map(|_| ()) 269 } 270 } 271 272 /// Sets the subject name of the certificate. 273 /// 274 /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools. 275 /// The `CN` field is used for the common name, such as a DNS name. 276 /// 277 /// ``` 278 /// use openssl::x509::{X509, X509NameBuilder}; 279 /// 280 /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap(); 281 /// x509_name.append_entry_by_text("C", "US").unwrap(); 282 /// x509_name.append_entry_by_text("ST", "CA").unwrap(); 283 /// x509_name.append_entry_by_text("O", "Some organization").unwrap(); 284 /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap(); 285 /// let x509_name = x509_name.build(); 286 /// 287 /// let mut x509 = openssl::x509::X509::builder().unwrap(); 288 /// x509.set_subject_name(&x509_name).unwrap(); 289 /// ``` 290 #[corresponds(X509_set_subject_name)] 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. 302 #[corresponds(X509_set_pubkey)] set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,303 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> 304 where 305 T: HasPublic, 306 { 307 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } 308 } 309 310 /// Returns a context object which is needed to create certain X509 extension values. 311 /// 312 /// Set `issuer` to `None` if the certificate will be self-signed. 313 #[corresponds(X509V3_set_ctx)] x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, conf: Option<&'a ConfRef>, ) -> X509v3Context<'a>314 pub fn x509v3_context<'a>( 315 &'a self, 316 issuer: Option<&'a X509Ref>, 317 conf: Option<&'a ConfRef>, 318 ) -> X509v3Context<'a> { 319 unsafe { 320 let mut ctx = mem::zeroed(); 321 322 let issuer = match issuer { 323 Some(issuer) => issuer.as_ptr(), 324 None => self.0.as_ptr(), 325 }; 326 let subject = self.0.as_ptr(); 327 ffi::X509V3_set_ctx( 328 &mut ctx, 329 issuer, 330 subject, 331 ptr::null_mut(), 332 ptr::null_mut(), 333 0, 334 ); 335 336 // nodb case taken care of since we zeroed ctx above 337 if let Some(conf) = conf { 338 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); 339 } 340 341 X509v3Context(ctx, PhantomData) 342 } 343 } 344 345 /// Adds an X509 extension value to the certificate. 346 /// 347 /// This works just as `append_extension` except it takes ownership of the `X509Extension`. append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack>348 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> { 349 self.append_extension2(&extension) 350 } 351 352 /// Adds an X509 extension value to the certificate. 353 #[corresponds(X509_add_ext)] append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack>354 pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> { 355 unsafe { 356 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; 357 Ok(()) 358 } 359 } 360 361 /// Signs the certificate with a private key. 362 #[corresponds(X509_sign)] 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 #[cfg(boringssl)] 387 type X509LenTy = c_uint; 388 #[cfg(not(boringssl))] 389 type X509LenTy = c_int; 390 391 impl X509Ref { 392 /// Returns this certificate's subject name. 393 #[corresponds(X509_get_subject_name)] subject_name(&self) -> &X509NameRef394 pub fn subject_name(&self) -> &X509NameRef { 395 unsafe { 396 let name = ffi::X509_get_subject_name(self.as_ptr()); 397 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") 398 } 399 } 400 401 /// Returns the hash of the certificates subject 402 #[corresponds(X509_subject_name_hash)] subject_name_hash(&self) -> u32403 pub fn subject_name_hash(&self) -> u32 { 404 #[allow(clippy::unnecessary_cast)] 405 unsafe { 406 ffi::X509_subject_name_hash(self.as_ptr()) as u32 407 } 408 } 409 410 /// Returns this certificate's issuer name. 411 #[corresponds(X509_get_issuer_name)] issuer_name(&self) -> &X509NameRef412 pub fn issuer_name(&self) -> &X509NameRef { 413 unsafe { 414 let name = ffi::X509_get_issuer_name(self.as_ptr()); 415 X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null") 416 } 417 } 418 419 /// Returns the hash of the certificates issuer 420 #[corresponds(X509_issuer_name_hash)] issuer_name_hash(&self) -> u32421 pub fn issuer_name_hash(&self) -> u32 { 422 #[allow(clippy::unnecessary_cast)] 423 unsafe { 424 ffi::X509_issuer_name_hash(self.as_ptr()) as u32 425 } 426 } 427 428 /// Returns this certificate's subject alternative name entries, if they exist. 429 #[corresponds(X509_get_ext_d2i)] subject_alt_names(&self) -> Option<Stack<GeneralName>>430 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> { 431 unsafe { 432 let stack = ffi::X509_get_ext_d2i( 433 self.as_ptr(), 434 ffi::NID_subject_alt_name, 435 ptr::null_mut(), 436 ptr::null_mut(), 437 ); 438 Stack::from_ptr_opt(stack as *mut _) 439 } 440 } 441 442 /// Returns this certificate's CRL distribution points, if they exist. 443 #[corresponds(X509_get_ext_d2i)] crl_distribution_points(&self) -> Option<Stack<DistPoint>>444 pub fn crl_distribution_points(&self) -> Option<Stack<DistPoint>> { 445 unsafe { 446 let stack = ffi::X509_get_ext_d2i( 447 self.as_ptr(), 448 ffi::NID_crl_distribution_points, 449 ptr::null_mut(), 450 ptr::null_mut(), 451 ); 452 Stack::from_ptr_opt(stack as *mut _) 453 } 454 } 455 456 /// Returns this certificate's issuer alternative name entries, if they exist. 457 #[corresponds(X509_get_ext_d2i)] issuer_alt_names(&self) -> Option<Stack<GeneralName>>458 pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> { 459 unsafe { 460 let stack = ffi::X509_get_ext_d2i( 461 self.as_ptr(), 462 ffi::NID_issuer_alt_name, 463 ptr::null_mut(), 464 ptr::null_mut(), 465 ); 466 Stack::from_ptr_opt(stack as *mut _) 467 } 468 } 469 470 /// Returns this certificate's [`authority information access`] entries, if they exist. 471 /// 472 /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1 473 #[corresponds(X509_get_ext_d2i)] authority_info(&self) -> Option<Stack<AccessDescription>>474 pub fn authority_info(&self) -> Option<Stack<AccessDescription>> { 475 unsafe { 476 let stack = ffi::X509_get_ext_d2i( 477 self.as_ptr(), 478 ffi::NID_info_access, 479 ptr::null_mut(), 480 ptr::null_mut(), 481 ); 482 Stack::from_ptr_opt(stack as *mut _) 483 } 484 } 485 486 /// Retrieves the path length extension from a certificate, if it exists. 487 #[corresponds(X509_get_pathlen)] 488 #[cfg(ossl110)] pathlen(&self) -> Option<u32>489 pub fn pathlen(&self) -> Option<u32> { 490 let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) }; 491 u32::try_from(v).ok() 492 } 493 494 /// Returns this certificate's subject key id, if it exists. 495 #[corresponds(X509_get0_subject_key_id)] 496 #[cfg(ossl110)] subject_key_id(&self) -> Option<&Asn1OctetStringRef>497 pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> { 498 unsafe { 499 let data = ffi::X509_get0_subject_key_id(self.as_ptr()); 500 Asn1OctetStringRef::from_const_ptr_opt(data) 501 } 502 } 503 504 /// Returns this certificate's authority key id, if it exists. 505 #[corresponds(X509_get0_authority_key_id)] 506 #[cfg(ossl110)] authority_key_id(&self) -> Option<&Asn1OctetStringRef>507 pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> { 508 unsafe { 509 let data = ffi::X509_get0_authority_key_id(self.as_ptr()); 510 Asn1OctetStringRef::from_const_ptr_opt(data) 511 } 512 } 513 514 /// Returns this certificate's authority issuer name entries, if they exist. 515 #[corresponds(X509_get0_authority_issuer)] 516 #[cfg(ossl111d)] authority_issuer(&self) -> Option<&StackRef<GeneralName>>517 pub fn authority_issuer(&self) -> Option<&StackRef<GeneralName>> { 518 unsafe { 519 let stack = ffi::X509_get0_authority_issuer(self.as_ptr()); 520 StackRef::from_const_ptr_opt(stack) 521 } 522 } 523 524 /// Returns this certificate's authority serial number, if it exists. 525 #[corresponds(X509_get0_authority_serial)] 526 #[cfg(ossl111d)] authority_serial(&self) -> Option<&Asn1IntegerRef>527 pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> { 528 unsafe { 529 let r = ffi::X509_get0_authority_serial(self.as_ptr()); 530 Asn1IntegerRef::from_const_ptr_opt(r) 531 } 532 } 533 534 #[corresponds(X509_get_pubkey)] public_key(&self) -> Result<PKey<Public>, ErrorStack>535 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> { 536 unsafe { 537 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?; 538 Ok(PKey::from_ptr(pkey)) 539 } 540 } 541 542 /// Returns a digest of the DER representation of the certificate. 543 #[corresponds(X509_digest)] digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack>544 pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> { 545 unsafe { 546 let mut digest = DigestBytes { 547 buf: [0; ffi::EVP_MAX_MD_SIZE as usize], 548 len: ffi::EVP_MAX_MD_SIZE as usize, 549 }; 550 let mut len = ffi::EVP_MAX_MD_SIZE as c_uint; 551 cvt(ffi::X509_digest( 552 self.as_ptr(), 553 hash_type.as_ptr(), 554 digest.buf.as_mut_ptr() as *mut _, 555 &mut len, 556 ))?; 557 digest.len = len as usize; 558 559 Ok(digest) 560 } 561 } 562 563 #[deprecated(since = "0.10.9", note = "renamed to digest")] fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack>564 pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> { 565 self.digest(hash_type).map(|b| b.to_vec()) 566 } 567 568 /// Returns the certificate's Not After validity period. 569 #[corresponds(X509_getm_notAfter)] not_after(&self) -> &Asn1TimeRef570 pub fn not_after(&self) -> &Asn1TimeRef { 571 unsafe { 572 let date = X509_getm_notAfter(self.as_ptr()); 573 Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null") 574 } 575 } 576 577 /// Returns the certificate's Not Before validity period. 578 #[corresponds(X509_getm_notBefore)] not_before(&self) -> &Asn1TimeRef579 pub fn not_before(&self) -> &Asn1TimeRef { 580 unsafe { 581 let date = X509_getm_notBefore(self.as_ptr()); 582 Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null") 583 } 584 } 585 586 /// Returns the certificate's signature 587 #[corresponds(X509_get0_signature)] signature(&self) -> &Asn1BitStringRef588 pub fn signature(&self) -> &Asn1BitStringRef { 589 unsafe { 590 let mut signature = ptr::null(); 591 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); 592 Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null") 593 } 594 } 595 596 /// Returns the certificate's signature algorithm. 597 #[corresponds(X509_get0_signature)] signature_algorithm(&self) -> &X509AlgorithmRef598 pub fn signature_algorithm(&self) -> &X509AlgorithmRef { 599 unsafe { 600 let mut algor = ptr::null(); 601 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); 602 X509AlgorithmRef::from_const_ptr_opt(algor) 603 .expect("signature algorithm must not be null") 604 } 605 } 606 607 /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information 608 /// Access field. 609 #[corresponds(X509_get1_ocsp)] ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack>610 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> { 611 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) } 612 } 613 614 /// Checks that this certificate issued `subject`. 615 #[corresponds(X509_check_issued)] issued(&self, subject: &X509Ref) -> X509VerifyResult616 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult { 617 unsafe { 618 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr()); 619 X509VerifyResult::from_raw(r) 620 } 621 } 622 623 /// Returns certificate version. If this certificate has no explicit version set, it defaults to 624 /// version 1. 625 /// 626 /// Note that `0` return value stands for version 1, `1` for version 2 and so on. 627 #[corresponds(X509_get_version)] 628 #[cfg(ossl110)] 629 #[allow(clippy::unnecessary_cast)] version(&self) -> i32630 pub fn version(&self) -> i32 { 631 unsafe { ffi::X509_get_version(self.as_ptr()) as i32 } 632 } 633 634 /// Check if the certificate is signed using the given public key. 635 /// 636 /// Only the signature is checked: no other checks (such as certificate chain validity) 637 /// are performed. 638 /// 639 /// Returns `true` if verification succeeds. 640 #[corresponds(X509_verify)] verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,641 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 642 where 643 T: HasPublic, 644 { 645 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 646 } 647 648 /// Returns this certificate's serial number. 649 #[corresponds(X509_get_serialNumber)] serial_number(&self) -> &Asn1IntegerRef650 pub fn serial_number(&self) -> &Asn1IntegerRef { 651 unsafe { 652 let r = ffi::X509_get_serialNumber(self.as_ptr()); 653 Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null") 654 } 655 } 656 657 to_pem! { 658 /// Serializes the certificate into a PEM-encoded X509 structure. 659 /// 660 /// The output will have a header of `-----BEGIN CERTIFICATE-----`. 661 #[corresponds(PEM_write_bio_X509)] 662 to_pem, 663 ffi::PEM_write_bio_X509 664 } 665 666 to_der! { 667 /// Serializes the certificate into a DER-encoded X509 structure. 668 #[corresponds(i2d_X509)] 669 to_der, 670 ffi::i2d_X509 671 } 672 673 to_pem! { 674 /// Converts the certificate to human readable text. 675 #[corresponds(X509_print)] 676 to_text, 677 ffi::X509_print 678 } 679 } 680 681 impl ToOwned for X509Ref { 682 type Owned = X509; 683 to_owned(&self) -> X509684 fn to_owned(&self) -> X509 { 685 unsafe { 686 X509_up_ref(self.as_ptr()); 687 X509::from_ptr(self.as_ptr()) 688 } 689 } 690 } 691 692 impl Ord for X509Ref { cmp(&self, other: &Self) -> cmp::Ordering693 fn cmp(&self, other: &Self) -> cmp::Ordering { 694 // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than. 695 // It can't fail if both pointers are valid, which we know is true. 696 let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) }; 697 cmp.cmp(&0) 698 } 699 } 700 701 impl PartialOrd for X509Ref { partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>702 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { 703 Some(self.cmp(other)) 704 } 705 } 706 707 impl PartialOrd<X509> for X509Ref { partial_cmp(&self, other: &X509) -> Option<cmp::Ordering>708 fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> { 709 <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other) 710 } 711 } 712 713 impl PartialEq for X509Ref { eq(&self, other: &Self) -> bool714 fn eq(&self, other: &Self) -> bool { 715 self.cmp(other) == cmp::Ordering::Equal 716 } 717 } 718 719 impl PartialEq<X509> for X509Ref { eq(&self, other: &X509) -> bool720 fn eq(&self, other: &X509) -> bool { 721 <X509Ref as PartialEq<X509Ref>>::eq(self, other) 722 } 723 } 724 725 impl Eq for X509Ref {} 726 727 impl X509 { 728 /// Returns a new builder. builder() -> Result<X509Builder, ErrorStack>729 pub fn builder() -> Result<X509Builder, ErrorStack> { 730 X509Builder::new() 731 } 732 733 from_pem! { 734 /// Deserializes a PEM-encoded X509 structure. 735 /// 736 /// The input should have a header of `-----BEGIN CERTIFICATE-----`. 737 #[corresponds(PEM_read_bio_X509)] 738 from_pem, 739 X509, 740 ffi::PEM_read_bio_X509 741 } 742 743 from_der! { 744 /// Deserializes a DER-encoded X509 structure. 745 #[corresponds(d2i_X509)] 746 from_der, 747 X509, 748 ffi::d2i_X509 749 } 750 751 /// Deserializes a list of PEM-formatted certificates. 752 #[corresponds(PEM_read_bio_X509)] stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack>753 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> { 754 unsafe { 755 ffi::init(); 756 let bio = MemBioSlice::new(pem)?; 757 758 let mut certs = vec![]; 759 loop { 760 let r = 761 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()); 762 if r.is_null() { 763 let err = ffi::ERR_peek_last_error(); 764 if ffi::ERR_GET_LIB(err) as X509LenTy == ffi::ERR_LIB_PEM 765 && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE 766 { 767 ffi::ERR_clear_error(); 768 break; 769 } 770 771 return Err(ErrorStack::get()); 772 } else { 773 certs.push(X509(r)); 774 } 775 } 776 777 Ok(certs) 778 } 779 } 780 } 781 782 impl Clone for X509 { clone(&self) -> X509783 fn clone(&self) -> X509 { 784 X509Ref::to_owned(self) 785 } 786 } 787 788 impl fmt::Debug for X509 { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result789 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 790 let serial = match &self.serial_number().to_bn() { 791 Ok(bn) => match bn.to_hex_str() { 792 Ok(hex) => hex.to_string(), 793 Err(_) => "".to_string(), 794 }, 795 Err(_) => "".to_string(), 796 }; 797 let mut debug_struct = formatter.debug_struct("X509"); 798 debug_struct.field("serial_number", &serial); 799 debug_struct.field("signature_algorithm", &self.signature_algorithm().object()); 800 debug_struct.field("issuer", &self.issuer_name()); 801 debug_struct.field("subject", &self.subject_name()); 802 if let Some(subject_alt_names) = &self.subject_alt_names() { 803 debug_struct.field("subject_alt_names", subject_alt_names); 804 } 805 debug_struct.field("not_before", &self.not_before()); 806 debug_struct.field("not_after", &self.not_after()); 807 808 if let Ok(public_key) = &self.public_key() { 809 debug_struct.field("public_key", public_key); 810 }; 811 // TODO: Print extensions once they are supported on the X509 struct. 812 813 debug_struct.finish() 814 } 815 } 816 817 impl AsRef<X509Ref> for X509Ref { as_ref(&self) -> &X509Ref818 fn as_ref(&self) -> &X509Ref { 819 self 820 } 821 } 822 823 impl Stackable for X509 { 824 type StackType = ffi::stack_st_X509; 825 } 826 827 impl Ord for X509 { cmp(&self, other: &Self) -> cmp::Ordering828 fn cmp(&self, other: &Self) -> cmp::Ordering { 829 X509Ref::cmp(self, other) 830 } 831 } 832 833 impl PartialOrd for X509 { partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>834 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { 835 X509Ref::partial_cmp(self, other) 836 } 837 } 838 839 impl PartialOrd<X509Ref> for X509 { partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering>840 fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> { 841 X509Ref::partial_cmp(self, other) 842 } 843 } 844 845 impl PartialEq for X509 { eq(&self, other: &Self) -> bool846 fn eq(&self, other: &Self) -> bool { 847 X509Ref::eq(self, other) 848 } 849 } 850 851 impl PartialEq<X509Ref> for X509 { eq(&self, other: &X509Ref) -> bool852 fn eq(&self, other: &X509Ref) -> bool { 853 X509Ref::eq(self, other) 854 } 855 } 856 857 impl Eq for X509 {} 858 859 /// A context object required to construct certain `X509` extension values. 860 pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>); 861 862 impl<'a> X509v3Context<'a> { as_ptr(&self) -> *mut ffi::X509V3_CTX863 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX { 864 &self.0 as *const _ as *mut _ 865 } 866 } 867 868 foreign_type_and_impl_send_sync! { 869 type CType = ffi::X509_EXTENSION; 870 fn drop = ffi::X509_EXTENSION_free; 871 872 /// Permit additional fields to be added to an `X509` v3 certificate. 873 pub struct X509Extension; 874 /// Reference to `X509Extension`. 875 pub struct X509ExtensionRef; 876 } 877 878 impl Stackable for X509Extension { 879 type StackType = ffi::stack_st_X509_EXTENSION; 880 } 881 882 impl X509Extension { 883 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported 884 /// names and their value formats. 885 /// 886 /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be 887 /// provided. 888 /// 889 /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL 890 /// mini-language that can read arbitrary files. 891 /// 892 /// See the extension module for builder types which will construct certain common extensions. 893 /// 894 /// This function is deprecated, `X509Extension::new_from_der` or the 895 /// types in `x509::extension` should be used in its place. 896 #[deprecated( 897 note = "Use x509::extension types or new_from_der instead", 898 since = "0.10.51" 899 )] new( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: &str, value: &str, ) -> Result<X509Extension, ErrorStack>900 pub fn new( 901 conf: Option<&ConfRef>, 902 context: Option<&X509v3Context<'_>>, 903 name: &str, 904 value: &str, 905 ) -> Result<X509Extension, ErrorStack> { 906 let name = CString::new(name).unwrap(); 907 let value = CString::new(value).unwrap(); 908 let mut ctx; 909 unsafe { 910 ffi::init(); 911 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); 912 let context_ptr = match context { 913 Some(c) => c.as_ptr(), 914 None => { 915 ctx = mem::zeroed(); 916 917 ffi::X509V3_set_ctx( 918 &mut ctx, 919 ptr::null_mut(), 920 ptr::null_mut(), 921 ptr::null_mut(), 922 ptr::null_mut(), 923 0, 924 ); 925 &mut ctx 926 } 927 }; 928 let name = name.as_ptr() as *mut _; 929 let value = value.as_ptr() as *mut _; 930 931 cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value)).map(X509Extension) 932 } 933 } 934 935 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported 936 /// extensions and their value formats. 937 /// 938 /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to 939 /// be provided. 940 /// 941 /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL 942 /// mini-language that can read arbitrary files. 943 /// 944 /// See the extension module for builder types which will construct certain common extensions. 945 /// 946 /// This function is deprecated, `X509Extension::new_from_der` or the 947 /// types in `x509::extension` should be used in its place. 948 #[deprecated( 949 note = "Use x509::extension types or new_from_der instead", 950 since = "0.10.51" 951 )] new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: Nid, value: &str, ) -> Result<X509Extension, ErrorStack>952 pub fn new_nid( 953 conf: Option<&ConfRef>, 954 context: Option<&X509v3Context<'_>>, 955 name: Nid, 956 value: &str, 957 ) -> Result<X509Extension, ErrorStack> { 958 let value = CString::new(value).unwrap(); 959 let mut ctx; 960 unsafe { 961 ffi::init(); 962 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); 963 let context_ptr = match context { 964 Some(c) => c.as_ptr(), 965 None => { 966 ctx = mem::zeroed(); 967 968 ffi::X509V3_set_ctx( 969 &mut ctx, 970 ptr::null_mut(), 971 ptr::null_mut(), 972 ptr::null_mut(), 973 ptr::null_mut(), 974 0, 975 ); 976 &mut ctx 977 } 978 }; 979 let name = name.as_raw(); 980 let value = value.as_ptr() as *mut _; 981 982 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension) 983 } 984 } 985 986 /// Constructs a new X509 extension value from its OID, whether it's 987 /// critical, and its DER contents. 988 /// 989 /// The extent structure of the DER value will vary based on the 990 /// extension type, and can generally be found in the RFC defining the 991 /// extension. 992 /// 993 /// For common extension types, there are Rust APIs provided in 994 /// `openssl::x509::extensions` which are more ergonomic. new_from_der( oid: &Asn1ObjectRef, critical: bool, der_contents: &Asn1OctetStringRef, ) -> Result<X509Extension, ErrorStack>995 pub fn new_from_der( 996 oid: &Asn1ObjectRef, 997 critical: bool, 998 der_contents: &Asn1OctetStringRef, 999 ) -> Result<X509Extension, ErrorStack> { 1000 unsafe { 1001 cvt_p(ffi::X509_EXTENSION_create_by_OBJ( 1002 ptr::null_mut(), 1003 oid.as_ptr(), 1004 critical as _, 1005 der_contents.as_ptr(), 1006 )) 1007 .map(X509Extension) 1008 } 1009 } 1010 new_internal( nid: Nid, critical: bool, value: *mut c_void, ) -> Result<X509Extension, ErrorStack>1011 pub(crate) unsafe fn new_internal( 1012 nid: Nid, 1013 critical: bool, 1014 value: *mut c_void, 1015 ) -> Result<X509Extension, ErrorStack> { 1016 ffi::init(); 1017 cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension) 1018 } 1019 1020 /// Adds an alias for an extension 1021 /// 1022 /// # Safety 1023 /// 1024 /// This method modifies global state without locking and therefore is not thread safe 1025 #[corresponds(X509V3_EXT_add_alias)] 1026 #[deprecated( 1027 note = "Use x509::extension types or new_from_der and then this is not necessary", 1028 since = "0.10.51" 1029 )] add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack>1030 pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> { 1031 ffi::init(); 1032 cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ()) 1033 } 1034 } 1035 1036 impl X509ExtensionRef { 1037 to_der! { 1038 /// Serializes the Extension to its standard DER encoding. 1039 #[corresponds(i2d_X509_EXTENSION)] 1040 to_der, 1041 ffi::i2d_X509_EXTENSION 1042 } 1043 } 1044 1045 /// A builder used to construct an `X509Name`. 1046 pub struct X509NameBuilder(X509Name); 1047 1048 impl X509NameBuilder { 1049 /// Creates a new builder. new() -> Result<X509NameBuilder, ErrorStack>1050 pub fn new() -> Result<X509NameBuilder, ErrorStack> { 1051 unsafe { 1052 ffi::init(); 1053 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p))) 1054 } 1055 } 1056 1057 /// Add a name entry 1058 #[corresponds(X509_NAME_add_entry)] 1059 #[cfg(any(ossl101, libressl350))] append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack>1060 pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> { 1061 unsafe { 1062 cvt(ffi::X509_NAME_add_entry( 1063 self.0.as_ptr(), 1064 ne.as_ptr(), 1065 -1, 1066 0, 1067 )) 1068 .map(|_| ()) 1069 } 1070 } 1071 1072 /// Add a field entry by str. 1073 /// 1074 /// This corresponds to [`X509_NAME_add_entry_by_txt`]. 1075 /// 1076 /// [`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>1077 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { 1078 unsafe { 1079 let field = CString::new(field).unwrap(); 1080 assert!(value.len() <= crate::SLenType::max_value() as usize); 1081 cvt(ffi::X509_NAME_add_entry_by_txt( 1082 self.0.as_ptr(), 1083 field.as_ptr() as *mut _, 1084 ffi::MBSTRING_UTF8, 1085 value.as_ptr(), 1086 value.len() as crate::SLenType, 1087 -1, 1088 0, 1089 )) 1090 .map(|_| ()) 1091 } 1092 } 1093 1094 /// Add a field entry by str with a specific type. 1095 /// 1096 /// This corresponds to [`X509_NAME_add_entry_by_txt`]. 1097 /// 1098 /// [`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>1099 pub fn append_entry_by_text_with_type( 1100 &mut self, 1101 field: &str, 1102 value: &str, 1103 ty: Asn1Type, 1104 ) -> Result<(), ErrorStack> { 1105 unsafe { 1106 let field = CString::new(field).unwrap(); 1107 assert!(value.len() <= crate::SLenType::max_value() as usize); 1108 cvt(ffi::X509_NAME_add_entry_by_txt( 1109 self.0.as_ptr(), 1110 field.as_ptr() as *mut _, 1111 ty.as_raw(), 1112 value.as_ptr(), 1113 value.len() as crate::SLenType, 1114 -1, 1115 0, 1116 )) 1117 .map(|_| ()) 1118 } 1119 } 1120 1121 /// Add a field entry by NID. 1122 /// 1123 /// This corresponds to [`X509_NAME_add_entry_by_NID`]. 1124 /// 1125 /// [`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>1126 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { 1127 unsafe { 1128 assert!(value.len() <= crate::SLenType::max_value() as usize); 1129 cvt(ffi::X509_NAME_add_entry_by_NID( 1130 self.0.as_ptr(), 1131 field.as_raw(), 1132 ffi::MBSTRING_UTF8, 1133 value.as_ptr() as *mut _, 1134 value.len() as crate::SLenType, 1135 -1, 1136 0, 1137 )) 1138 .map(|_| ()) 1139 } 1140 } 1141 1142 /// Add a field entry by NID with a specific type. 1143 /// 1144 /// This corresponds to [`X509_NAME_add_entry_by_NID`]. 1145 /// 1146 /// [`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>1147 pub fn append_entry_by_nid_with_type( 1148 &mut self, 1149 field: Nid, 1150 value: &str, 1151 ty: Asn1Type, 1152 ) -> Result<(), ErrorStack> { 1153 unsafe { 1154 assert!(value.len() <= crate::SLenType::max_value() as usize); 1155 cvt(ffi::X509_NAME_add_entry_by_NID( 1156 self.0.as_ptr(), 1157 field.as_raw(), 1158 ty.as_raw(), 1159 value.as_ptr() as *mut _, 1160 value.len() as crate::SLenType, 1161 -1, 1162 0, 1163 )) 1164 .map(|_| ()) 1165 } 1166 } 1167 1168 /// Return an `X509Name`. build(self) -> X509Name1169 pub fn build(self) -> X509Name { 1170 // Round-trip through bytes because OpenSSL is not const correct and 1171 // names in a "modified" state compute various things lazily. This can 1172 // lead to data-races because OpenSSL doesn't have locks or anything. 1173 X509Name::from_der(&self.0.to_der().unwrap()).unwrap() 1174 } 1175 } 1176 1177 foreign_type_and_impl_send_sync! { 1178 type CType = ffi::X509_NAME; 1179 fn drop = ffi::X509_NAME_free; 1180 1181 /// The names of an `X509` certificate. 1182 pub struct X509Name; 1183 /// Reference to `X509Name`. 1184 pub struct X509NameRef; 1185 } 1186 1187 impl X509Name { 1188 /// Returns a new builder. builder() -> Result<X509NameBuilder, ErrorStack>1189 pub fn builder() -> Result<X509NameBuilder, ErrorStack> { 1190 X509NameBuilder::new() 1191 } 1192 1193 /// Loads subject names from a file containing PEM-formatted certificates. 1194 /// 1195 /// 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>1196 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> { 1197 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); 1198 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) } 1199 } 1200 1201 from_der! { 1202 /// Deserializes a DER-encoded X509 name structure. 1203 /// 1204 /// This corresponds to [`d2i_X509_NAME`]. 1205 /// 1206 /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html 1207 from_der, 1208 X509Name, 1209 ffi::d2i_X509_NAME 1210 } 1211 } 1212 1213 impl Stackable for X509Name { 1214 type StackType = ffi::stack_st_X509_NAME; 1215 } 1216 1217 impl X509NameRef { 1218 /// Returns the name entries by the nid. entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_>1219 pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> { 1220 X509NameEntries { 1221 name: self, 1222 nid: Some(nid), 1223 loc: -1, 1224 } 1225 } 1226 1227 /// Returns an iterator over all `X509NameEntry` values entries(&self) -> X509NameEntries<'_>1228 pub fn entries(&self) -> X509NameEntries<'_> { 1229 X509NameEntries { 1230 name: self, 1231 nid: None, 1232 loc: -1, 1233 } 1234 } 1235 1236 /// Compare two names, like [`Ord`] but it may fail. 1237 /// 1238 /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp` 1239 /// call fails. 1240 /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may 1241 /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails. 1242 #[corresponds(X509_NAME_cmp)] try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack>1243 pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> { 1244 let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) }; 1245 if cfg!(ossl300) && cmp == -2 { 1246 return Err(ErrorStack::get()); 1247 } 1248 Ok(cmp.cmp(&0)) 1249 } 1250 1251 /// Copies the name to a new `X509Name`. 1252 #[corresponds(X509_NAME_dup)] 1253 #[cfg(any(boringssl, ossl110, libressl270))] to_owned(&self) -> Result<X509Name, ErrorStack>1254 pub fn to_owned(&self) -> Result<X509Name, ErrorStack> { 1255 unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) } 1256 } 1257 1258 to_der! { 1259 /// Serializes the certificate into a DER-encoded X509 name structure. 1260 /// 1261 /// This corresponds to [`i2d_X509_NAME`]. 1262 /// 1263 /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_NAME.html 1264 to_der, 1265 ffi::i2d_X509_NAME 1266 } 1267 } 1268 1269 impl fmt::Debug for X509NameRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1270 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1271 formatter.debug_list().entries(self.entries()).finish() 1272 } 1273 } 1274 1275 /// A type to destructure and examine an `X509Name`. 1276 pub struct X509NameEntries<'a> { 1277 name: &'a X509NameRef, 1278 nid: Option<Nid>, 1279 loc: c_int, 1280 } 1281 1282 impl<'a> Iterator for X509NameEntries<'a> { 1283 type Item = &'a X509NameEntryRef; 1284 next(&mut self) -> Option<&'a X509NameEntryRef>1285 fn next(&mut self) -> Option<&'a X509NameEntryRef> { 1286 unsafe { 1287 match self.nid { 1288 Some(nid) => { 1289 // There is a `Nid` specified to search for 1290 self.loc = 1291 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc); 1292 if self.loc == -1 { 1293 return None; 1294 } 1295 } 1296 None => { 1297 // Iterate over all `Nid`s 1298 self.loc += 1; 1299 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) { 1300 return None; 1301 } 1302 } 1303 } 1304 1305 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); 1306 1307 Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null")) 1308 } 1309 } 1310 } 1311 1312 foreign_type_and_impl_send_sync! { 1313 type CType = ffi::X509_NAME_ENTRY; 1314 fn drop = ffi::X509_NAME_ENTRY_free; 1315 1316 /// A name entry associated with a `X509Name`. 1317 pub struct X509NameEntry; 1318 /// Reference to `X509NameEntry`. 1319 pub struct X509NameEntryRef; 1320 } 1321 1322 impl X509NameEntryRef { 1323 /// Returns the field value of an `X509NameEntry`. 1324 /// 1325 /// This corresponds to [`X509_NAME_ENTRY_get_data`]. 1326 /// 1327 /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_data.html data(&self) -> &Asn1StringRef1328 pub fn data(&self) -> &Asn1StringRef { 1329 unsafe { 1330 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); 1331 Asn1StringRef::from_ptr(data) 1332 } 1333 } 1334 1335 /// Returns the `Asn1Object` value of an `X509NameEntry`. 1336 /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`. 1337 /// 1338 /// This corresponds to [`X509_NAME_ENTRY_get_object`]. 1339 /// 1340 /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_object.html object(&self) -> &Asn1ObjectRef1341 pub fn object(&self) -> &Asn1ObjectRef { 1342 unsafe { 1343 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); 1344 Asn1ObjectRef::from_ptr(object) 1345 } 1346 } 1347 } 1348 1349 impl fmt::Debug for X509NameEntryRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result1350 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1351 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data())) 1352 } 1353 } 1354 1355 /// A builder used to construct an `X509Req`. 1356 pub struct X509ReqBuilder(X509Req); 1357 1358 impl X509ReqBuilder { 1359 /// Returns a builder for a certificate request. 1360 /// 1361 /// This corresponds to [`X509_REQ_new`]. 1362 /// 1363 ///[`X509_REQ_new`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_new.html new() -> Result<X509ReqBuilder, ErrorStack>1364 pub fn new() -> Result<X509ReqBuilder, ErrorStack> { 1365 unsafe { 1366 ffi::init(); 1367 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) 1368 } 1369 } 1370 1371 /// Set the numerical value of the version field. 1372 /// 1373 /// This corresponds to [`X509_REQ_set_version`]. 1374 /// 1375 ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_version.html 1376 #[allow(clippy::useless_conversion)] set_version(&mut self, version: i32) -> Result<(), ErrorStack>1377 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { 1378 unsafe { 1379 cvt(ffi::X509_REQ_set_version( 1380 self.0.as_ptr(), 1381 version as c_long, 1382 )) 1383 .map(|_| ()) 1384 } 1385 } 1386 1387 /// Set the issuer name. 1388 /// 1389 /// This corresponds to [`X509_REQ_set_subject_name`]. 1390 /// 1391 /// [`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>1392 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { 1393 unsafe { 1394 cvt(ffi::X509_REQ_set_subject_name( 1395 self.0.as_ptr(), 1396 subject_name.as_ptr(), 1397 )) 1398 .map(|_| ()) 1399 } 1400 } 1401 1402 /// Set the public key. 1403 /// 1404 /// This corresponds to [`X509_REQ_set_pubkey`]. 1405 /// 1406 /// [`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,1407 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> 1408 where 1409 T: HasPublic, 1410 { 1411 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } 1412 } 1413 1414 /// Return an `X509v3Context`. This context object can be used to construct 1415 /// certain `X509` extensions. x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a>1416 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> { 1417 unsafe { 1418 let mut ctx = mem::zeroed(); 1419 1420 ffi::X509V3_set_ctx( 1421 &mut ctx, 1422 ptr::null_mut(), 1423 ptr::null_mut(), 1424 self.0.as_ptr(), 1425 ptr::null_mut(), 1426 0, 1427 ); 1428 1429 // nodb case taken care of since we zeroed ctx above 1430 if let Some(conf) = conf { 1431 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); 1432 } 1433 1434 X509v3Context(ctx, PhantomData) 1435 } 1436 } 1437 1438 /// Permits any number of extension fields to be added to the certificate. add_extensions( &mut self, extensions: &StackRef<X509Extension>, ) -> Result<(), ErrorStack>1439 pub fn add_extensions( 1440 &mut self, 1441 extensions: &StackRef<X509Extension>, 1442 ) -> Result<(), ErrorStack> { 1443 unsafe { 1444 cvt(ffi::X509_REQ_add_extensions( 1445 self.0.as_ptr(), 1446 extensions.as_ptr(), 1447 )) 1448 .map(|_| ()) 1449 } 1450 } 1451 1452 /// Sign the request using a private key. 1453 /// 1454 /// This corresponds to [`X509_REQ_sign`]. 1455 /// 1456 /// [`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,1457 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> 1458 where 1459 T: HasPrivate, 1460 { 1461 unsafe { 1462 cvt(ffi::X509_REQ_sign( 1463 self.0.as_ptr(), 1464 key.as_ptr(), 1465 hash.as_ptr(), 1466 )) 1467 .map(|_| ()) 1468 } 1469 } 1470 1471 /// Returns the `X509Req`. build(self) -> X509Req1472 pub fn build(self) -> X509Req { 1473 self.0 1474 } 1475 } 1476 1477 foreign_type_and_impl_send_sync! { 1478 type CType = ffi::X509_REQ; 1479 fn drop = ffi::X509_REQ_free; 1480 1481 /// An `X509` certificate request. 1482 pub struct X509Req; 1483 /// Reference to `X509Req`. 1484 pub struct X509ReqRef; 1485 } 1486 1487 impl X509Req { 1488 /// A builder for `X509Req`. builder() -> Result<X509ReqBuilder, ErrorStack>1489 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> { 1490 X509ReqBuilder::new() 1491 } 1492 1493 from_pem! { 1494 /// Deserializes a PEM-encoded PKCS#10 certificate request structure. 1495 /// 1496 /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`. 1497 /// 1498 /// This corresponds to [`PEM_read_bio_X509_REQ`]. 1499 /// 1500 /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_read_bio_X509_REQ.html 1501 from_pem, 1502 X509Req, 1503 ffi::PEM_read_bio_X509_REQ 1504 } 1505 1506 from_der! { 1507 /// Deserializes a DER-encoded PKCS#10 certificate request structure. 1508 /// 1509 /// This corresponds to [`d2i_X509_REQ`]. 1510 /// 1511 /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/d2i_X509_REQ.html 1512 from_der, 1513 X509Req, 1514 ffi::d2i_X509_REQ 1515 } 1516 } 1517 1518 impl X509ReqRef { 1519 to_pem! { 1520 /// Serializes the certificate request to a PEM-encoded PKCS#10 structure. 1521 /// 1522 /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`. 1523 /// 1524 /// This corresponds to [`PEM_write_bio_X509_REQ`]. 1525 /// 1526 /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_write_bio_X509_REQ.html 1527 to_pem, 1528 ffi::PEM_write_bio_X509_REQ 1529 } 1530 1531 to_der! { 1532 /// Serializes the certificate request to a DER-encoded PKCS#10 structure. 1533 /// 1534 /// This corresponds to [`i2d_X509_REQ`]. 1535 /// 1536 /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_REQ.html 1537 to_der, 1538 ffi::i2d_X509_REQ 1539 } 1540 1541 to_pem! { 1542 /// Converts the request to human readable text. 1543 #[corresponds(X509_Req_print)] 1544 to_text, 1545 ffi::X509_REQ_print 1546 } 1547 1548 /// Returns the numerical value of the version field of the certificate request. 1549 /// 1550 /// This corresponds to [`X509_REQ_get_version`] 1551 /// 1552 /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html 1553 #[allow(clippy::unnecessary_cast)] version(&self) -> i321554 pub fn version(&self) -> i32 { 1555 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } 1556 } 1557 1558 /// Returns the subject name of the certificate request. 1559 /// 1560 /// This corresponds to [`X509_REQ_get_subject_name`] 1561 /// 1562 /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_subject_name.html subject_name(&self) -> &X509NameRef1563 pub fn subject_name(&self) -> &X509NameRef { 1564 unsafe { 1565 let name = X509_REQ_get_subject_name(self.as_ptr()); 1566 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") 1567 } 1568 } 1569 1570 /// Returns the public key of the certificate request. 1571 /// 1572 /// This corresponds to [`X509_REQ_get_pubkey"] 1573 /// 1574 /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_pubkey.html public_key(&self) -> Result<PKey<Public>, ErrorStack>1575 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> { 1576 unsafe { 1577 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?; 1578 Ok(PKey::from_ptr(key)) 1579 } 1580 } 1581 1582 /// Check if the certificate request is signed using the given public key. 1583 /// 1584 /// Returns `true` if verification succeeds. 1585 /// 1586 /// This corresponds to [`X509_REQ_verify"]. 1587 /// 1588 /// [`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,1589 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 1590 where 1591 T: HasPublic, 1592 { 1593 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 1594 } 1595 1596 /// Returns the extensions of the certificate request. 1597 /// 1598 /// This corresponds to [`X509_REQ_get_extensions"] extensions(&self) -> Result<Stack<X509Extension>, ErrorStack>1599 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> { 1600 unsafe { 1601 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?; 1602 Ok(Stack::from_ptr(extensions)) 1603 } 1604 } 1605 } 1606 1607 /// The reason that a certificate was revoked. 1608 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 1609 pub struct CrlReason(c_int); 1610 1611 #[allow(missing_docs)] // no need to document the constants 1612 impl CrlReason { 1613 pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED); 1614 pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE); 1615 pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE); 1616 pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED); 1617 pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED); 1618 pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION); 1619 pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD); 1620 pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL); 1621 pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN); 1622 pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE); 1623 1624 /// Constructs an `CrlReason` from a raw OpenSSL value. from_raw(value: c_int) -> Self1625 pub const fn from_raw(value: c_int) -> Self { 1626 CrlReason(value) 1627 } 1628 1629 /// Returns the raw OpenSSL value represented by this type. as_raw(&self) -> c_int1630 pub const fn as_raw(&self) -> c_int { 1631 self.0 1632 } 1633 } 1634 1635 foreign_type_and_impl_send_sync! { 1636 type CType = ffi::X509_REVOKED; 1637 fn drop = ffi::X509_REVOKED_free; 1638 1639 /// An `X509` certificate revocation status. 1640 pub struct X509Revoked; 1641 /// Reference to `X509Revoked`. 1642 pub struct X509RevokedRef; 1643 } 1644 1645 impl Stackable for X509Revoked { 1646 type StackType = ffi::stack_st_X509_REVOKED; 1647 } 1648 1649 impl X509Revoked { 1650 from_der! { 1651 /// Deserializes a DER-encoded certificate revocation status 1652 #[corresponds(d2i_X509_REVOKED)] 1653 from_der, 1654 X509Revoked, 1655 ffi::d2i_X509_REVOKED 1656 } 1657 } 1658 1659 impl X509RevokedRef { 1660 to_der! { 1661 /// Serializes the certificate request to a DER-encoded certificate revocation status 1662 #[corresponds(d2i_X509_REVOKED)] 1663 to_der, 1664 ffi::i2d_X509_REVOKED 1665 } 1666 1667 /// Copies the entry to a new `X509Revoked`. 1668 #[corresponds(X509_NAME_dup)] 1669 #[cfg(any(boringssl, ossl110, libressl270))] to_owned(&self) -> Result<X509Revoked, ErrorStack>1670 pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> { 1671 unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) } 1672 } 1673 1674 /// Get the date that the certificate was revoked 1675 #[corresponds(X509_REVOKED_get0_revocationDate)] revocation_date(&self) -> &Asn1TimeRef1676 pub fn revocation_date(&self) -> &Asn1TimeRef { 1677 unsafe { 1678 let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _); 1679 assert!(!r.is_null()); 1680 Asn1TimeRef::from_ptr(r as *mut _) 1681 } 1682 } 1683 1684 /// Get the serial number of the revoked certificate 1685 #[corresponds(X509_REVOKED_get0_serialNumber)] serial_number(&self) -> &Asn1IntegerRef1686 pub fn serial_number(&self) -> &Asn1IntegerRef { 1687 unsafe { 1688 let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _); 1689 assert!(!r.is_null()); 1690 Asn1IntegerRef::from_ptr(r as *mut _) 1691 } 1692 } 1693 1694 /// Get the criticality and value of an extension. 1695 /// 1696 /// This returns None if the extension is not present or occurs multiple times. 1697 #[corresponds(X509_REVOKED_get_ext_d2i)] extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack>1698 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> { 1699 let mut critical = -1; 1700 let out = unsafe { 1701 // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED. 1702 let ext = ffi::X509_REVOKED_get_ext_d2i( 1703 self.as_ptr(), 1704 T::NID.as_raw(), 1705 &mut critical as *mut _, 1706 ptr::null_mut(), 1707 ); 1708 // SAFETY: Extensions's contract promises that the type returned by 1709 // OpenSSL here is T::Output. 1710 T::Output::from_ptr_opt(ext as *mut _) 1711 }; 1712 match (critical, out) { 1713 (0, Some(out)) => Ok(Some((false, out))), 1714 (1, Some(out)) => Ok(Some((true, out))), 1715 // -1 means the extension wasn't found, -2 means multiple were found. 1716 (-1 | -2, _) => Ok(None), 1717 // A critical value of 0 or 1 suggests success, but a null pointer 1718 // was returned so something went wrong. 1719 (0 | 1, None) => Err(ErrorStack::get()), 1720 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical), 1721 } 1722 } 1723 } 1724 1725 /// The CRL entry extension identifying the reason for revocation see [`CrlReason`], 1726 /// this is as defined in RFC 5280 Section 5.3.1. 1727 pub enum ReasonCode {} 1728 1729 // SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC 1730 // and in OpenSSL. 1731 unsafe impl ExtensionType for ReasonCode { 1732 const NID: Nid = Nid::from_raw(ffi::NID_crl_reason); 1733 1734 type Output = Asn1Enumerated; 1735 } 1736 1737 /// The CRL entry extension identifying the issuer of a certificate used in 1738 /// indirect CRLs, as defined in RFC 5280 Section 5.3.3. 1739 pub enum CertificateIssuer {} 1740 1741 // SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC 1742 // and in OpenSSL. 1743 unsafe impl ExtensionType for CertificateIssuer { 1744 const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer); 1745 1746 type Output = Stack<GeneralName>; 1747 } 1748 1749 foreign_type_and_impl_send_sync! { 1750 type CType = ffi::X509_CRL; 1751 fn drop = ffi::X509_CRL_free; 1752 1753 /// An `X509` certificate revocation list. 1754 pub struct X509Crl; 1755 /// Reference to `X509Crl`. 1756 pub struct X509CrlRef; 1757 } 1758 1759 /// The status of a certificate in a revoction list 1760 /// 1761 /// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods. 1762 /// 1763 /// [`X509_CRL_get0_by_*`]: https://www.openssl.org/docs/man1.1.0/man3/X509_CRL_get0_by_serial.html 1764 pub enum CrlStatus<'a> { 1765 /// The certificate is not present in the list 1766 NotRevoked, 1767 /// The certificate is in the list and is revoked 1768 Revoked(&'a X509RevokedRef), 1769 /// The certificate is in the list, but has the "removeFromCrl" status. 1770 /// 1771 /// This can occur if the certificate was revoked with the "CertificateHold" 1772 /// reason, and has since been unrevoked. 1773 RemoveFromCrl(&'a X509RevokedRef), 1774 } 1775 1776 impl<'a> CrlStatus<'a> { 1777 // Helper used by the X509_CRL_get0_by_* methods to convert their return 1778 // value to the status enum. 1779 // Safety note: the returned CrlStatus must not outlive the owner of the 1780 // revoked_entry pointer. from_ffi_status( status: c_int, revoked_entry: *mut ffi::X509_REVOKED, ) -> CrlStatus<'a>1781 unsafe fn from_ffi_status( 1782 status: c_int, 1783 revoked_entry: *mut ffi::X509_REVOKED, 1784 ) -> CrlStatus<'a> { 1785 match status { 1786 0 => CrlStatus::NotRevoked, 1787 1 => { 1788 assert!(!revoked_entry.is_null()); 1789 CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry)) 1790 } 1791 2 => { 1792 assert!(!revoked_entry.is_null()); 1793 CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry)) 1794 } 1795 _ => unreachable!( 1796 "{}", 1797 "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2." 1798 ), 1799 } 1800 } 1801 } 1802 1803 impl X509Crl { 1804 from_pem! { 1805 /// Deserializes a PEM-encoded Certificate Revocation List 1806 /// 1807 /// The input should have a header of `-----BEGIN X509 CRL-----`. 1808 #[corresponds(PEM_read_bio_X509_CRL)] 1809 from_pem, 1810 X509Crl, 1811 ffi::PEM_read_bio_X509_CRL 1812 } 1813 1814 from_der! { 1815 /// Deserializes a DER-encoded Certificate Revocation List 1816 #[corresponds(d2i_X509_CRL)] 1817 from_der, 1818 X509Crl, 1819 ffi::d2i_X509_CRL 1820 } 1821 } 1822 1823 impl X509CrlRef { 1824 to_pem! { 1825 /// Serializes the certificate request to a PEM-encoded Certificate Revocation List. 1826 /// 1827 /// The output will have a header of `-----BEGIN X509 CRL-----`. 1828 #[corresponds(PEM_write_bio_X509_CRL)] 1829 to_pem, 1830 ffi::PEM_write_bio_X509_CRL 1831 } 1832 1833 to_der! { 1834 /// Serializes the certificate request to a DER-encoded Certificate Revocation List. 1835 #[corresponds(i2d_X509_CRL)] 1836 to_der, 1837 ffi::i2d_X509_CRL 1838 } 1839 1840 /// Get the stack of revocation entries get_revoked(&self) -> Option<&StackRef<X509Revoked>>1841 pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> { 1842 unsafe { 1843 let revoked = X509_CRL_get_REVOKED(self.as_ptr()); 1844 if revoked.is_null() { 1845 None 1846 } else { 1847 Some(StackRef::from_ptr(revoked)) 1848 } 1849 } 1850 } 1851 1852 /// Returns the CRL's `lastUpdate` time. 1853 #[corresponds(X509_CRL_get0_lastUpdate)] last_update(&self) -> &Asn1TimeRef1854 pub fn last_update(&self) -> &Asn1TimeRef { 1855 unsafe { 1856 let date = X509_CRL_get0_lastUpdate(self.as_ptr()); 1857 assert!(!date.is_null()); 1858 Asn1TimeRef::from_ptr(date as *mut _) 1859 } 1860 } 1861 1862 /// Returns the CRL's `nextUpdate` time. 1863 /// 1864 /// If the `nextUpdate` field is missing, returns `None`. 1865 #[corresponds(X509_CRL_get0_nextUpdate)] next_update(&self) -> Option<&Asn1TimeRef>1866 pub fn next_update(&self) -> Option<&Asn1TimeRef> { 1867 unsafe { 1868 let date = X509_CRL_get0_nextUpdate(self.as_ptr()); 1869 Asn1TimeRef::from_const_ptr_opt(date) 1870 } 1871 } 1872 1873 /// Get the revocation status of a certificate by its serial number 1874 #[corresponds(X509_CRL_get0_by_serial)] get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a>1875 pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> { 1876 unsafe { 1877 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>(); 1878 let status = 1879 ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr()); 1880 CrlStatus::from_ffi_status(status, ret) 1881 } 1882 } 1883 1884 /// Get the revocation status of a certificate 1885 #[corresponds(X509_CRL_get0_by_cert)] get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a>1886 pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> { 1887 unsafe { 1888 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>(); 1889 let status = 1890 ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr()); 1891 CrlStatus::from_ffi_status(status, ret) 1892 } 1893 } 1894 1895 /// Get the issuer name from the revocation list. 1896 #[corresponds(X509_CRL_get_issuer)] issuer_name(&self) -> &X509NameRef1897 pub fn issuer_name(&self) -> &X509NameRef { 1898 unsafe { 1899 let name = X509_CRL_get_issuer(self.as_ptr()); 1900 assert!(!name.is_null()); 1901 X509NameRef::from_ptr(name) 1902 } 1903 } 1904 1905 /// Check if the CRL is signed using the given public key. 1906 /// 1907 /// Only the signature is checked: no other checks (such as certificate chain validity) 1908 /// are performed. 1909 /// 1910 /// Returns `true` if verification succeeds. 1911 #[corresponds(X509_CRL_verify)] verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,1912 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 1913 where 1914 T: HasPublic, 1915 { 1916 unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 1917 } 1918 } 1919 1920 /// The result of peer certificate verification. 1921 #[derive(Copy, Clone, PartialEq, Eq)] 1922 pub struct X509VerifyResult(c_int); 1923 1924 impl fmt::Debug for X509VerifyResult { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1925 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 1926 fmt.debug_struct("X509VerifyResult") 1927 .field("code", &self.0) 1928 .field("error", &self.error_string()) 1929 .finish() 1930 } 1931 } 1932 1933 impl fmt::Display for X509VerifyResult { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1934 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 1935 fmt.write_str(self.error_string()) 1936 } 1937 } 1938 1939 impl Error for X509VerifyResult {} 1940 1941 impl X509VerifyResult { 1942 /// Creates an `X509VerifyResult` from a raw error number. 1943 /// 1944 /// # Safety 1945 /// 1946 /// Some methods on `X509VerifyResult` are not thread safe if the error 1947 /// number is invalid. from_raw(err: c_int) -> X509VerifyResult1948 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult { 1949 X509VerifyResult(err) 1950 } 1951 1952 /// Return the integer representation of an `X509VerifyResult`. 1953 #[allow(clippy::trivially_copy_pass_by_ref)] as_raw(&self) -> c_int1954 pub fn as_raw(&self) -> c_int { 1955 self.0 1956 } 1957 1958 /// Return a human readable error string from the verification error. 1959 /// 1960 /// This corresponds to [`X509_verify_cert_error_string`]. 1961 /// 1962 /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/manmaster/crypto/X509_verify_cert_error_string.html 1963 #[allow(clippy::trivially_copy_pass_by_ref)] error_string(&self) -> &'static str1964 pub fn error_string(&self) -> &'static str { 1965 ffi::init(); 1966 1967 unsafe { 1968 let s = ffi::X509_verify_cert_error_string(self.0 as c_long); 1969 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() 1970 } 1971 } 1972 1973 /// Successful peer certificate verification. 1974 pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK); 1975 /// Application verification failure. 1976 pub const APPLICATION_VERIFICATION: X509VerifyResult = 1977 X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION); 1978 } 1979 1980 foreign_type_and_impl_send_sync! { 1981 type CType = ffi::GENERAL_NAME; 1982 fn drop = ffi::GENERAL_NAME_free; 1983 1984 /// An `X509` certificate alternative names. 1985 pub struct GeneralName; 1986 /// Reference to `GeneralName`. 1987 pub struct GeneralNameRef; 1988 } 1989 1990 impl GeneralName { new( type_: c_int, asn1_type: Asn1Type, value: &[u8], ) -> Result<GeneralName, ErrorStack>1991 unsafe fn new( 1992 type_: c_int, 1993 asn1_type: Asn1Type, 1994 value: &[u8], 1995 ) -> Result<GeneralName, ErrorStack> { 1996 ffi::init(); 1997 let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?); 1998 (*gn.as_ptr()).type_ = type_; 1999 let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?; 2000 ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap()); 2001 2002 #[cfg(boringssl)] 2003 { 2004 (*gn.as_ptr()).d.ptr = s.cast(); 2005 } 2006 #[cfg(not(boringssl))] 2007 { 2008 (*gn.as_ptr()).d = s.cast(); 2009 } 2010 2011 Ok(gn) 2012 } 2013 new_email(email: &[u8]) -> Result<GeneralName, ErrorStack>2014 pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> { 2015 unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) } 2016 } 2017 new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack>2018 pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> { 2019 unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) } 2020 } 2021 new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack>2022 pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> { 2023 unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) } 2024 } 2025 new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack>2026 pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> { 2027 match ip { 2028 IpAddr::V4(addr) => unsafe { 2029 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets()) 2030 }, 2031 IpAddr::V6(addr) => unsafe { 2032 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets()) 2033 }, 2034 } 2035 } 2036 new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack>2037 pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> { 2038 unsafe { 2039 ffi::init(); 2040 let gn = cvt_p(ffi::GENERAL_NAME_new())?; 2041 (*gn).type_ = ffi::GEN_RID; 2042 2043 #[cfg(boringssl)] 2044 { 2045 (*gn).d.registeredID = oid.as_ptr(); 2046 } 2047 #[cfg(not(boringssl))] 2048 { 2049 (*gn).d = oid.as_ptr().cast(); 2050 } 2051 2052 mem::forget(oid); 2053 2054 Ok(GeneralName::from_ptr(gn)) 2055 } 2056 } 2057 new_other_name( oid: Asn1Object, value: &Vec<u8>, ) -> Result<GeneralName, ErrorStack>2058 pub(crate) fn new_other_name( 2059 oid: Asn1Object, 2060 value: &Vec<u8>, 2061 ) -> Result<GeneralName, ErrorStack> { 2062 unsafe { 2063 ffi::init(); 2064 2065 let typ = cvt_p(ffi::d2i_ASN1_TYPE( 2066 ptr::null_mut(), 2067 &mut value.as_ptr().cast(), 2068 value.len().try_into().unwrap(), 2069 ))?; 2070 2071 let gn = cvt_p(ffi::GENERAL_NAME_new())?; 2072 (*gn).type_ = ffi::GEN_OTHERNAME; 2073 2074 if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername( 2075 gn, 2076 oid.as_ptr().cast(), 2077 typ, 2078 )) { 2079 ffi::GENERAL_NAME_free(gn); 2080 return Err(e); 2081 } 2082 2083 mem::forget(oid); 2084 2085 Ok(GeneralName::from_ptr(gn)) 2086 } 2087 } 2088 } 2089 2090 impl GeneralNameRef { ia5_string(&self, ffi_type: c_int) -> Option<&str>2091 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { 2092 unsafe { 2093 if (*self.as_ptr()).type_ != ffi_type { 2094 return None; 2095 } 2096 2097 #[cfg(boringssl)] 2098 let d = (*self.as_ptr()).d.ptr; 2099 #[cfg(not(boringssl))] 2100 let d = (*self.as_ptr()).d; 2101 2102 let ptr = ASN1_STRING_get0_data(d as *mut _); 2103 let len = ffi::ASN1_STRING_length(d as *mut _); 2104 2105 let slice = slice::from_raw_parts(ptr as *const u8, len as usize); 2106 // IA5Strings are stated to be ASCII (specifically IA5). Hopefully 2107 // OpenSSL checks that when loading a certificate but if not we'll 2108 // use this instead of from_utf8_unchecked just in case. 2109 str::from_utf8(slice).ok() 2110 } 2111 } 2112 2113 /// Returns the contents of this `GeneralName` if it is an `rfc822Name`. email(&self) -> Option<&str>2114 pub fn email(&self) -> Option<&str> { 2115 self.ia5_string(ffi::GEN_EMAIL) 2116 } 2117 2118 /// Returns the contents of this `GeneralName` if it is a `directoryName`. directory_name(&self) -> Option<&X509NameRef>2119 pub fn directory_name(&self) -> Option<&X509NameRef> { 2120 unsafe { 2121 if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME { 2122 return None; 2123 } 2124 2125 #[cfg(boringssl)] 2126 let d = (*self.as_ptr()).d.ptr; 2127 #[cfg(not(boringssl))] 2128 let d = (*self.as_ptr()).d; 2129 2130 Some(X509NameRef::from_const_ptr(d as *const _)) 2131 } 2132 } 2133 2134 /// Returns the contents of this `GeneralName` if it is a `dNSName`. dnsname(&self) -> Option<&str>2135 pub fn dnsname(&self) -> Option<&str> { 2136 self.ia5_string(ffi::GEN_DNS) 2137 } 2138 2139 /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`. uri(&self) -> Option<&str>2140 pub fn uri(&self) -> Option<&str> { 2141 self.ia5_string(ffi::GEN_URI) 2142 } 2143 2144 /// Returns the contents of this `GeneralName` if it is an `iPAddress`. ipaddress(&self) -> Option<&[u8]>2145 pub fn ipaddress(&self) -> Option<&[u8]> { 2146 unsafe { 2147 if (*self.as_ptr()).type_ != ffi::GEN_IPADD { 2148 return None; 2149 } 2150 #[cfg(boringssl)] 2151 let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d); 2152 #[cfg(not(boringssl))] 2153 let d = (*self.as_ptr()).d; 2154 2155 let ptr = ASN1_STRING_get0_data(d as *mut _); 2156 let len = ffi::ASN1_STRING_length(d as *mut _); 2157 2158 Some(slice::from_raw_parts(ptr as *const u8, len as usize)) 2159 } 2160 } 2161 } 2162 2163 impl fmt::Debug for GeneralNameRef { fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result2164 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 2165 if let Some(email) = self.email() { 2166 formatter.write_str(email) 2167 } else if let Some(dnsname) = self.dnsname() { 2168 formatter.write_str(dnsname) 2169 } else if let Some(uri) = self.uri() { 2170 formatter.write_str(uri) 2171 } else if let Some(ipaddress) = self.ipaddress() { 2172 let address = <[u8; 16]>::try_from(ipaddress) 2173 .map(IpAddr::from) 2174 .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from)); 2175 match address { 2176 Ok(a) => fmt::Debug::fmt(&a, formatter), 2177 Err(_) => fmt::Debug::fmt(ipaddress, formatter), 2178 } 2179 } else { 2180 formatter.write_str("(empty)") 2181 } 2182 } 2183 } 2184 2185 impl Stackable for GeneralName { 2186 type StackType = ffi::stack_st_GENERAL_NAME; 2187 } 2188 2189 foreign_type_and_impl_send_sync! { 2190 type CType = ffi::DIST_POINT; 2191 fn drop = ffi::DIST_POINT_free; 2192 2193 /// A `X509` distribution point. 2194 pub struct DistPoint; 2195 /// Reference to `DistPoint`. 2196 pub struct DistPointRef; 2197 } 2198 2199 impl DistPointRef { 2200 /// Returns the name of this distribution point if it exists distpoint(&self) -> Option<&DistPointNameRef>2201 pub fn distpoint(&self) -> Option<&DistPointNameRef> { 2202 unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) } 2203 } 2204 } 2205 2206 foreign_type_and_impl_send_sync! { 2207 type CType = ffi::DIST_POINT_NAME; 2208 fn drop = ffi::DIST_POINT_NAME_free; 2209 2210 /// A `X509` distribution point. 2211 pub struct DistPointName; 2212 /// Reference to `DistPointName`. 2213 pub struct DistPointNameRef; 2214 } 2215 2216 impl DistPointNameRef { 2217 /// Returns the contents of this DistPointName if it is a fullname. fullname(&self) -> Option<&StackRef<GeneralName>>2218 pub fn fullname(&self) -> Option<&StackRef<GeneralName>> { 2219 unsafe { 2220 if (*self.as_ptr()).type_ != 0 { 2221 return None; 2222 } 2223 StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname) 2224 } 2225 } 2226 } 2227 2228 impl Stackable for DistPoint { 2229 type StackType = ffi::stack_st_DIST_POINT; 2230 } 2231 2232 foreign_type_and_impl_send_sync! { 2233 type CType = ffi::ACCESS_DESCRIPTION; 2234 fn drop = ffi::ACCESS_DESCRIPTION_free; 2235 2236 /// `AccessDescription` of certificate authority information. 2237 pub struct AccessDescription; 2238 /// Reference to `AccessDescription`. 2239 pub struct AccessDescriptionRef; 2240 } 2241 2242 impl AccessDescriptionRef { 2243 /// Returns the access method OID. method(&self) -> &Asn1ObjectRef2244 pub fn method(&self) -> &Asn1ObjectRef { 2245 unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) } 2246 } 2247 2248 // Returns the access location. location(&self) -> &GeneralNameRef2249 pub fn location(&self) -> &GeneralNameRef { 2250 unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) } 2251 } 2252 } 2253 2254 impl Stackable for AccessDescription { 2255 type StackType = ffi::stack_st_ACCESS_DESCRIPTION; 2256 } 2257 2258 foreign_type_and_impl_send_sync! { 2259 type CType = ffi::X509_ALGOR; 2260 fn drop = ffi::X509_ALGOR_free; 2261 2262 /// An `X509` certificate signature algorithm. 2263 pub struct X509Algorithm; 2264 /// Reference to `X509Algorithm`. 2265 pub struct X509AlgorithmRef; 2266 } 2267 2268 impl X509AlgorithmRef { 2269 /// Returns the ASN.1 OID of this algorithm. object(&self) -> &Asn1ObjectRef2270 pub fn object(&self) -> &Asn1ObjectRef { 2271 unsafe { 2272 let mut oid = ptr::null(); 2273 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); 2274 Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null") 2275 } 2276 } 2277 } 2278 2279 foreign_type_and_impl_send_sync! { 2280 type CType = ffi::X509_OBJECT; 2281 fn drop = X509_OBJECT_free; 2282 2283 /// An `X509` or an X509 certificate revocation list. 2284 pub struct X509Object; 2285 /// Reference to `X509Object` 2286 pub struct X509ObjectRef; 2287 } 2288 2289 impl X509ObjectRef { x509(&self) -> Option<&X509Ref>2290 pub fn x509(&self) -> Option<&X509Ref> { 2291 unsafe { 2292 let ptr = X509_OBJECT_get0_X509(self.as_ptr()); 2293 X509Ref::from_const_ptr_opt(ptr) 2294 } 2295 } 2296 } 2297 2298 impl Stackable for X509Object { 2299 type StackType = ffi::stack_st_X509_OBJECT; 2300 } 2301 2302 cfg_if! { 2303 if #[cfg(any(boringssl, ossl110, libressl273))] { 2304 use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature}; 2305 } else { 2306 #[allow(bad_style)] 2307 unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { 2308 (*(*(*x).cert_info).validity).notAfter 2309 } 2310 2311 #[allow(bad_style)] 2312 unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { 2313 (*(*(*x).cert_info).validity).notBefore 2314 } 2315 2316 #[allow(bad_style)] 2317 unsafe fn X509_up_ref(x: *mut ffi::X509) { 2318 ffi::CRYPTO_add_lock( 2319 &mut (*x).references, 2320 1, 2321 ffi::CRYPTO_LOCK_X509, 2322 "mod.rs\0".as_ptr() as *const _, 2323 line!() as c_int, 2324 ); 2325 } 2326 2327 #[allow(bad_style)] 2328 unsafe fn X509_get0_signature( 2329 psig: *mut *const ffi::ASN1_BIT_STRING, 2330 palg: *mut *const ffi::X509_ALGOR, 2331 x: *const ffi::X509, 2332 ) { 2333 if !psig.is_null() { 2334 *psig = (*x).signature; 2335 } 2336 if !palg.is_null() { 2337 *palg = (*x).sig_alg; 2338 } 2339 } 2340 } 2341 } 2342 2343 cfg_if! { 2344 if #[cfg(any(boringssl, ossl110, libressl350))] { 2345 use ffi::{ 2346 X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter, 2347 X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name, 2348 }; 2349 } else { 2350 use ffi::{ 2351 ASN1_STRING_data as ASN1_STRING_get0_data, 2352 X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, 2353 X509_set_notAfter as X509_set1_notAfter, 2354 X509_set_notBefore as X509_set1_notBefore, 2355 }; 2356 2357 #[allow(bad_style)] 2358 unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { 2359 ffi::ASN1_INTEGER_get((*(*x).req_info).version) 2360 } 2361 2362 #[allow(bad_style)] 2363 unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { 2364 (*(*x).req_info).subject 2365 } 2366 2367 #[allow(bad_style)] 2368 unsafe fn X509_ALGOR_get0( 2369 paobj: *mut *const ffi::ASN1_OBJECT, 2370 pptype: *mut c_int, 2371 pval: *mut *mut ::libc::c_void, 2372 alg: *const ffi::X509_ALGOR, 2373 ) { 2374 if !paobj.is_null() { 2375 *paobj = (*alg).algorithm; 2376 } 2377 assert!(pptype.is_null()); 2378 assert!(pval.is_null()); 2379 } 2380 } 2381 } 2382 2383 cfg_if! { 2384 if #[cfg(any(ossl110, boringssl, libressl270))] { 2385 use ffi::X509_OBJECT_get0_X509; 2386 } else { 2387 #[allow(bad_style)] 2388 unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 { 2389 if (*x).type_ == ffi::X509_LU_X509 { 2390 (*x).data.x509 2391 } else { 2392 ptr::null_mut() 2393 } 2394 } 2395 } 2396 } 2397 2398 cfg_if! { 2399 if #[cfg(any(ossl110, libressl350))] { 2400 use ffi::X509_OBJECT_free; 2401 } else if #[cfg(boringssl)] { 2402 use ffi::X509_OBJECT_free_contents as X509_OBJECT_free; 2403 } else { 2404 #[allow(bad_style)] 2405 unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) { 2406 ffi::X509_OBJECT_free_contents(x); 2407 ffi::CRYPTO_free(x as *mut libc::c_void); 2408 } 2409 } 2410 } 2411 2412 cfg_if! { 2413 if #[cfg(any(ossl110, libressl350, boringssl))] { 2414 use ffi::{ 2415 X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate, 2416 X509_CRL_get_REVOKED, 2417 X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber, 2418 }; 2419 } else { 2420 #[allow(bad_style)] 2421 unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { 2422 (*(*x).crl).lastUpdate 2423 } 2424 #[allow(bad_style)] 2425 unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { 2426 (*(*x).crl).nextUpdate 2427 } 2428 #[allow(bad_style)] 2429 unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME { 2430 (*(*x).crl).issuer 2431 } 2432 #[allow(bad_style)] 2433 unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED { 2434 (*(*x).crl).revoked 2435 } 2436 #[allow(bad_style)] 2437 unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER { 2438 (*x).serialNumber 2439 } 2440 #[allow(bad_style)] 2441 unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME { 2442 (*x).revocationDate 2443 } 2444 } 2445 } 2446 2447 #[derive(Copy, Clone, PartialEq, Eq)] 2448 pub struct X509PurposeId(c_int); 2449 2450 impl X509PurposeId { 2451 pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT); 2452 pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER); 2453 pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER); 2454 pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN); 2455 pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT); 2456 pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN); 2457 pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY); 2458 pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER); 2459 pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN); 2460 2461 /// Constructs an `X509PurposeId` from a raw OpenSSL value. from_raw(id: c_int) -> Self2462 pub fn from_raw(id: c_int) -> Self { 2463 X509PurposeId(id) 2464 } 2465 2466 /// Returns the raw OpenSSL value represented by this type. as_raw(&self) -> c_int2467 pub fn as_raw(&self) -> c_int { 2468 self.0 2469 } 2470 } 2471 2472 /// A reference to an [`X509_PURPOSE`]. 2473 pub struct X509PurposeRef(Opaque); 2474 2475 /// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL. 2476 impl ForeignTypeRef for X509PurposeRef { 2477 type CType = ffi::X509_PURPOSE; 2478 } 2479 2480 impl X509PurposeRef { 2481 /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short 2482 /// names include 2483 /// - "sslclient", 2484 /// - "sslserver", 2485 /// - "nssslserver", 2486 /// - "smimesign", 2487 /// - "smimeencrypt", 2488 /// - "crlsign", 2489 /// - "any", 2490 /// - "ocsphelper", 2491 /// - "timestampsign" 2492 /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose. 2493 #[allow(clippy::unnecessary_cast)] get_by_sname(sname: &str) -> Result<c_int, ErrorStack>2494 pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> { 2495 unsafe { 2496 let sname = CString::new(sname).unwrap(); 2497 cfg_if! { 2498 if #[cfg(any(ossl110, libressl280))] { 2499 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?; 2500 } else { 2501 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?; 2502 } 2503 } 2504 Ok(purpose) 2505 } 2506 } 2507 /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g. 2508 /// `X509PurposeRef::get_by_sname()`. 2509 #[corresponds(X509_PURPOSE_get0)] from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack>2510 pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> { 2511 unsafe { 2512 let ptr = cvt_p(ffi::X509_PURPOSE_get0(idx))?; 2513 Ok(X509PurposeRef::from_ptr(ptr)) 2514 } 2515 } 2516 2517 /// Get the purpose value from an X509Purpose structure. This value is one of 2518 /// - `X509_PURPOSE_SSL_CLIENT` 2519 /// - `X509_PURPOSE_SSL_SERVER` 2520 /// - `X509_PURPOSE_NS_SSL_SERVER` 2521 /// - `X509_PURPOSE_SMIME_SIGN` 2522 /// - `X509_PURPOSE_SMIME_ENCRYPT` 2523 /// - `X509_PURPOSE_CRL_SIGN` 2524 /// - `X509_PURPOSE_ANY` 2525 /// - `X509_PURPOSE_OCSP_HELPER` 2526 /// - `X509_PURPOSE_TIMESTAMP_SIGN` purpose(&self) -> X509PurposeId2527 pub fn purpose(&self) -> X509PurposeId { 2528 unsafe { 2529 let x509_purpose: *mut ffi::X509_PURPOSE = self.as_ptr(); 2530 X509PurposeId::from_raw((*x509_purpose).purpose) 2531 } 2532 } 2533 } 2534