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