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