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. 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 68 pub fn new() -> Result<X509StoreContext, ErrorStack> { 69 unsafe { 70 ffi::init(); 71 cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext(p)) 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 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 98 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 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 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 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 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 200 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 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. 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. 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. 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. 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. 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. 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 /// ``` 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. 303 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> 304 where 305 T: HasPublic, 306 { 307 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } 308 } 309 310 /// Returns a context object which is needed to create certain X509 extension values. 311 /// 312 /// Set `issuer` to `None` if the certificate will be self-signed. 313 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 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> { 346 unsafe { 347 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; 348 mem::forget(extension); 349 Ok(()) 350 } 351 } 352 353 /// Signs the certificate with a private key. 354 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> 355 where 356 T: HasPrivate, 357 { 358 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) } 359 } 360 361 /// Consumes the builder, returning the certificate. 362 pub fn build(self) -> X509 { 363 self.0 364 } 365 } 366 367 foreign_type_and_impl_send_sync! { 368 type CType = ffi::X509; 369 fn drop = ffi::X509_free; 370 371 /// An `X509` public key certificate. 372 pub struct X509; 373 /// Reference to `X509`. 374 pub struct X509Ref; 375 } 376 377 impl X509Ref { 378 /// Returns this certificate's subject name. 379 /// 380 /// This corresponds to [`X509_get_subject_name`]. 381 /// 382 /// [`X509_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html 383 pub fn subject_name(&self) -> &X509NameRef { 384 unsafe { 385 let name = ffi::X509_get_subject_name(self.as_ptr()); 386 assert!(!name.is_null()); 387 X509NameRef::from_ptr(name) 388 } 389 } 390 391 /// Returns this certificate's issuer name. 392 /// 393 /// This corresponds to [`X509_get_issuer_name`]. 394 /// 395 /// [`X509_get_issuer_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html 396 pub fn issuer_name(&self) -> &X509NameRef { 397 unsafe { 398 let name = ffi::X509_get_issuer_name(self.as_ptr()); 399 assert!(!name.is_null()); 400 X509NameRef::from_ptr(name) 401 } 402 } 403 404 /// Returns this certificate's subject alternative name entries, if they exist. 405 /// 406 /// This corresponds to [`X509_get_ext_d2i`] called with `NID_subject_alt_name`. 407 /// 408 /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html 409 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> { 410 unsafe { 411 let stack = ffi::X509_get_ext_d2i( 412 self.as_ptr(), 413 ffi::NID_subject_alt_name, 414 ptr::null_mut(), 415 ptr::null_mut(), 416 ); 417 if stack.is_null() { 418 None 419 } else { 420 Some(Stack::from_ptr(stack as *mut _)) 421 } 422 } 423 } 424 425 /// Returns this certificate's issuer alternative name entries, if they exist. 426 /// 427 /// This corresponds to [`X509_get_ext_d2i`] called with `NID_issuer_alt_name`. 428 /// 429 /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html 430 pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> { 431 unsafe { 432 let stack = ffi::X509_get_ext_d2i( 433 self.as_ptr(), 434 ffi::NID_issuer_alt_name, 435 ptr::null_mut(), 436 ptr::null_mut(), 437 ); 438 if stack.is_null() { 439 None 440 } else { 441 Some(Stack::from_ptr(stack as *mut _)) 442 } 443 } 444 } 445 446 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> { 447 unsafe { 448 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?; 449 Ok(PKey::from_ptr(pkey)) 450 } 451 } 452 453 /// Returns a digest of the DER representation of the certificate. 454 /// 455 /// This corresponds to [`X509_digest`]. 456 /// 457 /// [`X509_digest`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_digest.html 458 pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> { 459 unsafe { 460 let mut digest = DigestBytes { 461 buf: [0; ffi::EVP_MAX_MD_SIZE as usize], 462 len: ffi::EVP_MAX_MD_SIZE as usize, 463 }; 464 let mut len = ffi::EVP_MAX_MD_SIZE; 465 cvt(ffi::X509_digest( 466 self.as_ptr(), 467 hash_type.as_ptr(), 468 digest.buf.as_mut_ptr() as *mut _, 469 &mut len, 470 ))?; 471 digest.len = len as usize; 472 473 Ok(digest) 474 } 475 } 476 477 #[deprecated(since = "0.10.9", note = "renamed to digest")] 478 pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> { 479 self.digest(hash_type).map(|b| b.to_vec()) 480 } 481 482 /// Returns the certificate's Not After validity period. 483 pub fn not_after(&self) -> &Asn1TimeRef { 484 unsafe { 485 let date = X509_getm_notAfter(self.as_ptr()); 486 assert!(!date.is_null()); 487 Asn1TimeRef::from_ptr(date) 488 } 489 } 490 491 /// Returns the certificate's Not Before validity period. 492 pub fn not_before(&self) -> &Asn1TimeRef { 493 unsafe { 494 let date = X509_getm_notBefore(self.as_ptr()); 495 assert!(!date.is_null()); 496 Asn1TimeRef::from_ptr(date) 497 } 498 } 499 500 /// Returns the certificate's signature 501 pub fn signature(&self) -> &Asn1BitStringRef { 502 unsafe { 503 let mut signature = ptr::null(); 504 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); 505 assert!(!signature.is_null()); 506 Asn1BitStringRef::from_ptr(signature as *mut _) 507 } 508 } 509 510 /// Returns the certificate's signature algorithm. 511 pub fn signature_algorithm(&self) -> &X509AlgorithmRef { 512 unsafe { 513 let mut algor = ptr::null(); 514 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); 515 assert!(!algor.is_null()); 516 X509AlgorithmRef::from_ptr(algor as *mut _) 517 } 518 } 519 520 /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information 521 /// Access field. 522 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> { 523 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) } 524 } 525 526 /// Checks that this certificate issued `subject`. 527 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult { 528 unsafe { 529 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr()); 530 X509VerifyResult::from_raw(r) 531 } 532 } 533 534 /// Check if the certificate is signed using the given public key. 535 /// 536 /// Only the signature is checked: no other checks (such as certificate chain validity) 537 /// are performed. 538 /// 539 /// Returns `true` if verification succeeds. 540 /// 541 /// This corresponds to [`X509_verify"]. 542 /// 543 /// [`X509_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify.html 544 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 545 where 546 T: HasPublic, 547 { 548 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 549 } 550 551 /// Returns this certificate's serial number. 552 /// 553 /// This corresponds to [`X509_get_serialNumber`]. 554 /// 555 /// [`X509_get_serialNumber`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_serialNumber.html 556 pub fn serial_number(&self) -> &Asn1IntegerRef { 557 unsafe { 558 let r = ffi::X509_get_serialNumber(self.as_ptr()); 559 assert!(!r.is_null()); 560 Asn1IntegerRef::from_ptr(r) 561 } 562 } 563 564 to_pem! { 565 /// Serializes the certificate into a PEM-encoded X509 structure. 566 /// 567 /// The output will have a header of `-----BEGIN CERTIFICATE-----`. 568 /// 569 /// This corresponds to [`PEM_write_bio_X509`]. 570 /// 571 /// [`PEM_write_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509.html 572 to_pem, 573 ffi::PEM_write_bio_X509 574 } 575 576 to_der! { 577 /// Serializes the certificate into a DER-encoded X509 structure. 578 /// 579 /// This corresponds to [`i2d_X509`]. 580 /// 581 /// [`i2d_X509`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509.html 582 to_der, 583 ffi::i2d_X509 584 } 585 } 586 587 impl ToOwned for X509Ref { 588 type Owned = X509; 589 590 fn to_owned(&self) -> X509 { 591 unsafe { 592 X509_up_ref(self.as_ptr()); 593 X509::from_ptr(self.as_ptr()) 594 } 595 } 596 } 597 598 impl X509 { 599 /// Returns a new builder. 600 pub fn builder() -> Result<X509Builder, ErrorStack> { 601 X509Builder::new() 602 } 603 604 from_pem! { 605 /// Deserializes a PEM-encoded X509 structure. 606 /// 607 /// The input should have a header of `-----BEGIN CERTIFICATE-----`. 608 /// 609 /// This corresponds to [`PEM_read_bio_X509`]. 610 /// 611 /// [`PEM_read_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509.html 612 from_pem, 613 X509, 614 ffi::PEM_read_bio_X509 615 } 616 617 from_der! { 618 /// Deserializes a DER-encoded X509 structure. 619 /// 620 /// This corresponds to [`d2i_X509`]. 621 /// 622 /// [`d2i_X509`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html 623 from_der, 624 X509, 625 ffi::d2i_X509 626 } 627 628 /// Deserializes a list of PEM-formatted certificates. 629 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> { 630 unsafe { 631 ffi::init(); 632 let bio = MemBioSlice::new(pem)?; 633 634 let mut certs = vec![]; 635 loop { 636 let r = 637 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()); 638 if r.is_null() { 639 let err = ffi::ERR_peek_last_error(); 640 if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM 641 && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE 642 { 643 ffi::ERR_clear_error(); 644 break; 645 } 646 647 return Err(ErrorStack::get()); 648 } else { 649 certs.push(X509(r)); 650 } 651 } 652 653 Ok(certs) 654 } 655 } 656 } 657 658 impl Clone for X509 { 659 fn clone(&self) -> X509 { 660 X509Ref::to_owned(self) 661 } 662 } 663 664 impl AsRef<X509Ref> for X509Ref { 665 fn as_ref(&self) -> &X509Ref { 666 self 667 } 668 } 669 670 impl Stackable for X509 { 671 type StackType = ffi::stack_st_X509; 672 } 673 674 /// A context object required to construct certain `X509` extension values. 675 pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>); 676 677 impl<'a> X509v3Context<'a> { 678 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX { 679 &self.0 as *const _ as *mut _ 680 } 681 } 682 683 foreign_type_and_impl_send_sync! { 684 type CType = ffi::X509_EXTENSION; 685 fn drop = ffi::X509_EXTENSION_free; 686 687 /// Permit additional fields to be added to an `X509` v3 certificate. 688 pub struct X509Extension; 689 /// Reference to `X509Extension`. 690 pub struct X509ExtensionRef; 691 } 692 693 impl Stackable for X509Extension { 694 type StackType = ffi::stack_st_X509_EXTENSION; 695 } 696 697 impl X509Extension { 698 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported 699 /// names and their value formats. 700 /// 701 /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be 702 /// provided. 703 /// 704 /// See the extension module for builder types which will construct certain common extensions. 705 pub fn new( 706 conf: Option<&ConfRef>, 707 context: Option<&X509v3Context>, 708 name: &str, 709 value: &str, 710 ) -> Result<X509Extension, ErrorStack> { 711 let name = CString::new(name).unwrap(); 712 let value = CString::new(value).unwrap(); 713 unsafe { 714 ffi::init(); 715 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); 716 let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); 717 let name = name.as_ptr() as *mut _; 718 let value = value.as_ptr() as *mut _; 719 720 cvt_p(ffi::X509V3_EXT_nconf(conf, context, name, value)).map(X509Extension) 721 } 722 } 723 724 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported 725 /// extensions and their value formats. 726 /// 727 /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to 728 /// be provided. 729 /// 730 /// See the extension module for builder types which will construct certain common extensions. 731 pub fn new_nid( 732 conf: Option<&ConfRef>, 733 context: Option<&X509v3Context>, 734 name: Nid, 735 value: &str, 736 ) -> Result<X509Extension, ErrorStack> { 737 let value = CString::new(value).unwrap(); 738 unsafe { 739 ffi::init(); 740 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); 741 let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); 742 let name = name.as_raw(); 743 let value = value.as_ptr() as *mut _; 744 745 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension) 746 } 747 } 748 } 749 750 /// A builder used to construct an `X509Name`. 751 pub struct X509NameBuilder(X509Name); 752 753 impl X509NameBuilder { 754 /// Creates a new builder. 755 pub fn new() -> Result<X509NameBuilder, ErrorStack> { 756 unsafe { 757 ffi::init(); 758 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p))) 759 } 760 } 761 762 /// Add a field entry by str. 763 /// 764 /// This corresponds to [`X509_NAME_add_entry_by_txt`]. 765 /// 766 /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html 767 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { 768 unsafe { 769 let field = CString::new(field).unwrap(); 770 assert!(value.len() <= c_int::max_value() as usize); 771 cvt(ffi::X509_NAME_add_entry_by_txt( 772 self.0.as_ptr(), 773 field.as_ptr() as *mut _, 774 ffi::MBSTRING_UTF8, 775 value.as_ptr(), 776 value.len() as c_int, 777 -1, 778 0, 779 )) 780 .map(|_| ()) 781 } 782 } 783 784 /// Add a field entry by NID. 785 /// 786 /// This corresponds to [`X509_NAME_add_entry_by_NID`]. 787 /// 788 /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html 789 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { 790 unsafe { 791 assert!(value.len() <= c_int::max_value() as usize); 792 cvt(ffi::X509_NAME_add_entry_by_NID( 793 self.0.as_ptr(), 794 field.as_raw(), 795 ffi::MBSTRING_UTF8, 796 value.as_ptr() as *mut _, 797 value.len() as c_int, 798 -1, 799 0, 800 )) 801 .map(|_| ()) 802 } 803 } 804 805 /// Return an `X509Name`. 806 pub fn build(self) -> X509Name { 807 self.0 808 } 809 } 810 811 foreign_type_and_impl_send_sync! { 812 type CType = ffi::X509_NAME; 813 fn drop = ffi::X509_NAME_free; 814 815 /// The names of an `X509` certificate. 816 pub struct X509Name; 817 /// Reference to `X509Name`. 818 pub struct X509NameRef; 819 } 820 821 impl X509Name { 822 /// Returns a new builder. 823 pub fn builder() -> Result<X509NameBuilder, ErrorStack> { 824 X509NameBuilder::new() 825 } 826 827 /// Loads subject names from a file containing PEM-formatted certificates. 828 /// 829 /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`. 830 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> { 831 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); 832 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) } 833 } 834 } 835 836 impl Stackable for X509Name { 837 type StackType = ffi::stack_st_X509_NAME; 838 } 839 840 impl X509NameRef { 841 /// Returns the name entries by the nid. 842 pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> { 843 X509NameEntries { 844 name: self, 845 nid: Some(nid), 846 loc: -1, 847 } 848 } 849 850 /// Returns an iterator over all `X509NameEntry` values 851 pub fn entries<'a>(&'a self) -> X509NameEntries<'a> { 852 X509NameEntries { 853 name: self, 854 nid: None, 855 loc: -1, 856 } 857 } 858 } 859 860 /// A type to destructure and examine an `X509Name`. 861 pub struct X509NameEntries<'a> { 862 name: &'a X509NameRef, 863 nid: Option<Nid>, 864 loc: c_int, 865 } 866 867 impl<'a> Iterator for X509NameEntries<'a> { 868 type Item = &'a X509NameEntryRef; 869 870 fn next(&mut self) -> Option<&'a X509NameEntryRef> { 871 unsafe { 872 match self.nid { 873 Some(nid) => { 874 // There is a `Nid` specified to search for 875 self.loc = 876 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc); 877 if self.loc == -1 { 878 return None; 879 } 880 } 881 None => { 882 // Iterate over all `Nid`s 883 self.loc += 1; 884 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) { 885 return None; 886 } 887 } 888 } 889 890 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); 891 assert!(!entry.is_null()); 892 893 Some(X509NameEntryRef::from_ptr(entry)) 894 } 895 } 896 } 897 898 foreign_type_and_impl_send_sync! { 899 type CType = ffi::X509_NAME_ENTRY; 900 fn drop = ffi::X509_NAME_ENTRY_free; 901 902 /// A name entry associated with a `X509Name`. 903 pub struct X509NameEntry; 904 /// Reference to `X509NameEntry`. 905 pub struct X509NameEntryRef; 906 } 907 908 impl X509NameEntryRef { 909 /// Returns the field value of an `X509NameEntry`. 910 /// 911 /// This corresponds to [`X509_NAME_ENTRY_get_data`]. 912 /// 913 /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html 914 pub fn data(&self) -> &Asn1StringRef { 915 unsafe { 916 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); 917 Asn1StringRef::from_ptr(data) 918 } 919 } 920 921 /// Returns the `Asn1Object` value of an `X509NameEntry`. 922 /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`. 923 /// 924 /// This corresponds to [`X509_NAME_ENTRY_get_object`]. 925 /// 926 /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html 927 pub fn object(&self) -> &Asn1ObjectRef { 928 unsafe { 929 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); 930 Asn1ObjectRef::from_ptr(object) 931 } 932 } 933 } 934 935 /// A builder used to construct an `X509Req`. 936 pub struct X509ReqBuilder(X509Req); 937 938 impl X509ReqBuilder { 939 /// Returns a builder for a certificate request. 940 /// 941 /// This corresponds to [`X509_REQ_new`]. 942 /// 943 ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html 944 pub fn new() -> Result<X509ReqBuilder, ErrorStack> { 945 unsafe { 946 ffi::init(); 947 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) 948 } 949 } 950 951 /// Set the numerical value of the version field. 952 /// 953 /// This corresponds to [`X509_REQ_set_version`]. 954 /// 955 ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html 956 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { 957 unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } 958 } 959 960 /// Set the issuer name. 961 /// 962 /// This corresponds to [`X509_REQ_set_subject_name`]. 963 /// 964 /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_subject_name.html 965 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { 966 unsafe { 967 cvt(ffi::X509_REQ_set_subject_name( 968 self.0.as_ptr(), 969 subject_name.as_ptr(), 970 )) 971 .map(|_| ()) 972 } 973 } 974 975 /// Set the public key. 976 /// 977 /// This corresponds to [`X509_REQ_set_pubkey`]. 978 /// 979 /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_pubkey.html 980 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> 981 where 982 T: HasPublic, 983 { 984 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } 985 } 986 987 /// Return an `X509v3Context`. This context object can be used to construct 988 /// certain `X509` extensions. 989 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> { 990 unsafe { 991 let mut ctx = mem::zeroed(); 992 993 ffi::X509V3_set_ctx( 994 &mut ctx, 995 ptr::null_mut(), 996 ptr::null_mut(), 997 self.0.as_ptr(), 998 ptr::null_mut(), 999 0, 1000 ); 1001 1002 // nodb case taken care of since we zeroed ctx above 1003 if let Some(conf) = conf { 1004 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); 1005 } 1006 1007 X509v3Context(ctx, PhantomData) 1008 } 1009 } 1010 1011 /// Permits any number of extension fields to be added to the certificate. 1012 pub fn add_extensions( 1013 &mut self, 1014 extensions: &StackRef<X509Extension>, 1015 ) -> Result<(), ErrorStack> { 1016 unsafe { 1017 cvt(ffi::X509_REQ_add_extensions( 1018 self.0.as_ptr(), 1019 extensions.as_ptr(), 1020 )) 1021 .map(|_| ()) 1022 } 1023 } 1024 1025 /// Sign the request using a private key. 1026 /// 1027 /// This corresponds to [`X509_REQ_sign`]. 1028 /// 1029 /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html 1030 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack> 1031 where 1032 T: HasPrivate, 1033 { 1034 unsafe { 1035 cvt(ffi::X509_REQ_sign( 1036 self.0.as_ptr(), 1037 key.as_ptr(), 1038 hash.as_ptr(), 1039 )) 1040 .map(|_| ()) 1041 } 1042 } 1043 1044 /// Returns the `X509Req`. 1045 pub fn build(self) -> X509Req { 1046 self.0 1047 } 1048 } 1049 1050 foreign_type_and_impl_send_sync! { 1051 type CType = ffi::X509_REQ; 1052 fn drop = ffi::X509_REQ_free; 1053 1054 /// An `X509` certificate request. 1055 pub struct X509Req; 1056 /// Reference to `X509Req`. 1057 pub struct X509ReqRef; 1058 } 1059 1060 impl X509Req { 1061 /// A builder for `X509Req`. 1062 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> { 1063 X509ReqBuilder::new() 1064 } 1065 1066 from_pem! { 1067 /// Deserializes a PEM-encoded PKCS#10 certificate request structure. 1068 /// 1069 /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`. 1070 /// 1071 /// This corresponds to [`PEM_read_bio_X509_REQ`]. 1072 /// 1073 /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html 1074 from_pem, 1075 X509Req, 1076 ffi::PEM_read_bio_X509_REQ 1077 } 1078 1079 from_der! { 1080 /// Deserializes a DER-encoded PKCS#10 certificate request structure. 1081 /// 1082 /// This corresponds to [`d2i_X509_REQ`]. 1083 /// 1084 /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html 1085 from_der, 1086 X509Req, 1087 ffi::d2i_X509_REQ 1088 } 1089 } 1090 1091 impl X509ReqRef { 1092 to_pem! { 1093 /// Serializes the certificate request to a PEM-encoded PKCS#10 structure. 1094 /// 1095 /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`. 1096 /// 1097 /// This corresponds to [`PEM_write_bio_X509_REQ`]. 1098 /// 1099 /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html 1100 to_pem, 1101 ffi::PEM_write_bio_X509_REQ 1102 } 1103 1104 to_der! { 1105 /// Serializes the certificate request to a DER-encoded PKCS#10 structure. 1106 /// 1107 /// This corresponds to [`i2d_X509_REQ`]. 1108 /// 1109 /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html 1110 to_der, 1111 ffi::i2d_X509_REQ 1112 } 1113 1114 /// Returns the numerical value of the version field of the certificate request. 1115 /// 1116 /// This corresponds to [`X509_REQ_get_version`] 1117 /// 1118 /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html 1119 pub fn version(&self) -> i32 { 1120 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } 1121 } 1122 1123 /// Returns the subject name of the certificate request. 1124 /// 1125 /// This corresponds to [`X509_REQ_get_subject_name`] 1126 /// 1127 /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html 1128 pub fn subject_name(&self) -> &X509NameRef { 1129 unsafe { 1130 let name = X509_REQ_get_subject_name(self.as_ptr()); 1131 assert!(!name.is_null()); 1132 X509NameRef::from_ptr(name) 1133 } 1134 } 1135 1136 /// Returns the public key of the certificate request. 1137 /// 1138 /// This corresponds to [`X509_REQ_get_pubkey"] 1139 /// 1140 /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html 1141 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> { 1142 unsafe { 1143 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?; 1144 Ok(PKey::from_ptr(key)) 1145 } 1146 } 1147 1148 /// Check if the certificate request is signed using the given public key. 1149 /// 1150 /// Returns `true` if verification succeeds. 1151 /// 1152 /// This corresponds to [`X509_REQ_verify"]. 1153 /// 1154 /// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html 1155 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack> 1156 where 1157 T: HasPublic, 1158 { 1159 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } 1160 } 1161 1162 /// Returns the extensions of the certificate request. 1163 /// 1164 /// This corresponds to [`X509_REQ_get_extensions"] 1165 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> { 1166 unsafe { 1167 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?; 1168 Ok(Stack::from_ptr(extensions)) 1169 } 1170 } 1171 } 1172 1173 /// The result of peer certificate verification. 1174 #[derive(Copy, Clone, PartialEq, Eq)] 1175 pub struct X509VerifyResult(c_int); 1176 1177 impl fmt::Debug for X509VerifyResult { 1178 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 1179 fmt.debug_struct("X509VerifyResult") 1180 .field("code", &self.0) 1181 .field("error", &self.error_string()) 1182 .finish() 1183 } 1184 } 1185 1186 impl fmt::Display for X509VerifyResult { 1187 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 1188 fmt.write_str(self.error_string()) 1189 } 1190 } 1191 1192 impl Error for X509VerifyResult { 1193 fn description(&self) -> &str { 1194 "an X509 validation error" 1195 } 1196 } 1197 1198 impl X509VerifyResult { 1199 /// Creates an `X509VerifyResult` from a raw error number. 1200 /// 1201 /// # Safety 1202 /// 1203 /// Some methods on `X509VerifyResult` are not thread safe if the error 1204 /// number is invalid. 1205 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult { 1206 X509VerifyResult(err) 1207 } 1208 1209 /// Return the integer representation of an `X509VerifyResult`. 1210 pub fn as_raw(&self) -> c_int { 1211 self.0 1212 } 1213 1214 /// Return a human readable error string from the verification error. 1215 /// 1216 /// This corresponds to [`X509_verify_cert_error_string`]. 1217 /// 1218 /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify_cert_error_string.html 1219 pub fn error_string(&self) -> &'static str { 1220 ffi::init(); 1221 1222 unsafe { 1223 let s = ffi::X509_verify_cert_error_string(self.0 as c_long); 1224 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() 1225 } 1226 } 1227 1228 /// Successful peer certifiate verification. 1229 pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK); 1230 /// Application verification failure. 1231 pub const APPLICATION_VERIFICATION: X509VerifyResult = 1232 X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION); 1233 } 1234 1235 foreign_type_and_impl_send_sync! { 1236 type CType = ffi::GENERAL_NAME; 1237 fn drop = ffi::GENERAL_NAME_free; 1238 1239 /// An `X509` certificate alternative names. 1240 pub struct GeneralName; 1241 /// Reference to `GeneralName`. 1242 pub struct GeneralNameRef; 1243 } 1244 1245 impl GeneralNameRef { 1246 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { 1247 unsafe { 1248 if (*self.as_ptr()).type_ != ffi_type { 1249 return None; 1250 } 1251 1252 let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); 1253 let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); 1254 1255 let slice = slice::from_raw_parts(ptr as *const u8, len as usize); 1256 // IA5Strings are stated to be ASCII (specifically IA5). Hopefully 1257 // OpenSSL checks that when loading a certificate but if not we'll 1258 // use this instead of from_utf8_unchecked just in case. 1259 str::from_utf8(slice).ok() 1260 } 1261 } 1262 1263 /// Returns the contents of this `GeneralName` if it is an `rfc822Name`. 1264 pub fn email(&self) -> Option<&str> { 1265 self.ia5_string(ffi::GEN_EMAIL) 1266 } 1267 1268 /// Returns the contents of this `GeneralName` if it is a `dNSName`. 1269 pub fn dnsname(&self) -> Option<&str> { 1270 self.ia5_string(ffi::GEN_DNS) 1271 } 1272 1273 /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`. 1274 pub fn uri(&self) -> Option<&str> { 1275 self.ia5_string(ffi::GEN_URI) 1276 } 1277 1278 /// Returns the contents of this `GeneralName` if it is an `iPAddress`. 1279 pub fn ipaddress(&self) -> Option<&[u8]> { 1280 unsafe { 1281 if (*self.as_ptr()).type_ != ffi::GEN_IPADD { 1282 return None; 1283 } 1284 1285 let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); 1286 let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); 1287 1288 Some(slice::from_raw_parts(ptr as *const u8, len as usize)) 1289 } 1290 } 1291 } 1292 1293 impl Stackable for GeneralName { 1294 type StackType = ffi::stack_st_GENERAL_NAME; 1295 } 1296 1297 foreign_type_and_impl_send_sync! { 1298 type CType = ffi::X509_ALGOR; 1299 fn drop = ffi::X509_ALGOR_free; 1300 1301 /// An `X509` certificate signature algorithm. 1302 pub struct X509Algorithm; 1303 /// Reference to `X509Algorithm`. 1304 pub struct X509AlgorithmRef; 1305 } 1306 1307 impl X509AlgorithmRef { 1308 /// Returns the ASN.1 OID of this algorithm. 1309 pub fn object(&self) -> &Asn1ObjectRef { 1310 unsafe { 1311 let mut oid = ptr::null(); 1312 X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); 1313 assert!(!oid.is_null()); 1314 Asn1ObjectRef::from_ptr(oid as *mut _) 1315 } 1316 } 1317 } 1318 1319 cfg_if! { 1320 if #[cfg(any(ossl110, libressl273))] { 1321 use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature}; 1322 } else { 1323 #[allow(bad_style)] 1324 unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { 1325 (*(*(*x).cert_info).validity).notAfter 1326 } 1327 1328 #[allow(bad_style)] 1329 unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { 1330 (*(*(*x).cert_info).validity).notBefore 1331 } 1332 1333 #[allow(bad_style)] 1334 unsafe fn X509_up_ref(x: *mut ffi::X509) { 1335 ffi::CRYPTO_add_lock( 1336 &mut (*x).references, 1337 1, 1338 ffi::CRYPTO_LOCK_X509, 1339 "mod.rs\0".as_ptr() as *const _, 1340 line!() as c_int, 1341 ); 1342 } 1343 1344 #[allow(bad_style)] 1345 unsafe fn X509_get0_signature( 1346 psig: *mut *const ffi::ASN1_BIT_STRING, 1347 palg: *mut *const ffi::X509_ALGOR, 1348 x: *const ffi::X509, 1349 ) { 1350 if !psig.is_null() { 1351 *psig = (*x).signature; 1352 } 1353 if !palg.is_null() { 1354 *palg = (*x).sig_alg; 1355 } 1356 } 1357 } 1358 } 1359 1360 cfg_if! { 1361 if #[cfg(ossl110)] { 1362 use ffi::{ 1363 X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter, 1364 X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name, 1365 }; 1366 } else { 1367 use ffi::{ 1368 ASN1_STRING_data as ASN1_STRING_get0_data, 1369 X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, 1370 X509_set_notAfter as X509_set1_notAfter, 1371 X509_set_notBefore as X509_set1_notBefore, 1372 }; 1373 1374 #[allow(bad_style)] 1375 unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { 1376 ffi::ASN1_INTEGER_get((*(*x).req_info).version) 1377 } 1378 1379 #[allow(bad_style)] 1380 unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { 1381 (*(*x).req_info).subject 1382 } 1383 1384 #[allow(bad_style)] 1385 unsafe fn X509_ALGOR_get0( 1386 paobj: *mut *const ffi::ASN1_OBJECT, 1387 pptype: *mut c_int, 1388 pval: *mut *mut ::libc::c_void, 1389 alg: *const ffi::X509_ALGOR, 1390 ) { 1391 if !paobj.is_null() { 1392 *paobj = (*alg).algorithm; 1393 } 1394 assert!(pptype.is_null()); 1395 assert!(pval.is_null()); 1396 } 1397 } 1398 } 1399