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