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