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