1 //! The standard defining the format of public key certificates.
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.
11 use foreign_types
::{ForeignType, ForeignTypeRef}
;
12 use libc
::{c_int, c_long}
;
13 use std
::error
::Error
;
14 use std
::ffi
::{CStr, CString}
;
16 use std
::marker
::PhantomData
;
23 use asn1
::{Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef}
;
26 use error
::ErrorStack
;
28 use hash
::{DigestBytes, MessageDigest}
;
30 use pkey
::{HasPrivate, HasPublic, PKey, PKeyRef, Public}
;
32 use stack
::{Stack, StackRef, Stackable}
;
33 use string
::OpensslString
;
34 use {cvt, cvt_n, cvt_p}
;
36 #[cfg(any(ossl102, libressl261))]
45 foreign_type_and_impl_send_sync
! {
46 type CType
= ffi
::X509_STORE_CTX
;
47 fn drop
= ffi
::X509_STORE_CTX_free
;
49 /// An `X509` certificate store context.
50 pub struct X509StoreContext
;
52 /// Reference to `X509StoreContext`.
53 pub struct X509StoreContextRef
;
56 impl X509StoreContext
{
57 /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a
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)) }
63 /// Creates a new `X509StoreContext` instance.
65 /// This corresponds to [`X509_STORE_CTX_new`].
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
> {
71 cvt_p(ffi
::X509_STORE_CTX_new()).map(X509StoreContext
)
76 impl X509StoreContextRef
{
77 /// Returns application data pertaining to an `X509` store context.
79 /// This corresponds to [`X509_STORE_CTX_get_ex_data`].
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
> {
84 let data
= ffi
::X509_STORE_CTX_get_ex_data(self.as_ptr(), index
.as_raw());
88 Some(&*(data
as *const T
))
93 /// Returns the error code of the context.
95 /// This corresponds to [`X509_STORE_CTX_get_error`].
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())) }
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.
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.
112 /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
113 /// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
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
119 trust
: &store
::X509StoreRef
,
121 cert_chain
: &StackRef
<X509
>,
123 ) -> Result
<T
, ErrorStack
>
125 F
: FnOnce(&mut X509StoreContextRef
) -> Result
<T
, ErrorStack
>,
127 struct Cleanup
<'a
>(&'a
mut X509StoreContextRef
);
129 impl<'a
> Drop
for Cleanup
<'a
> {
132 ffi
::X509_STORE_CTX_cleanup(self.0.as_ptr());
138 cvt(ffi
::X509_STORE_CTX_init(
145 let cleanup
= Cleanup(self);
146 with_context(cleanup
.0)
150 /// Verifies the stored certificate.
152 /// Returns `true` if verification succeeds. The `error` method will return the specific
153 /// validation error if the certificate was not valid.
155 /// This will only work inside of a call to `init`.
157 /// This corresponds to [`X509_verify_cert`].
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) }
164 /// Set the error code of the context.
166 /// This corresponds to [`X509_STORE_CTX_set_error`].
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
) {
171 ffi
::X509_STORE_CTX_set_error(self.as_ptr(), result
.as_raw());
175 /// Returns a reference to the certificate which caused the error or None if
176 /// no certificate is relevant to the error.
178 /// This corresponds to [`X509_STORE_CTX_get_current_cert`].
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
> {
183 let ptr
= ffi
::X509_STORE_CTX_get_current_cert(self.as_ptr());
187 Some(X509Ref
::from_ptr(ptr
))
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.
197 /// This corresponds to [`X509_STORE_CTX_get_error_depth`].
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 }
204 /// Returns a reference to a complete valid `X509` certificate chain.
206 /// This corresponds to [`X509_STORE_CTX_get0_chain`].
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
>> {
211 let chain
= X509_STORE_CTX_get0_chain(self.as_ptr());
216 Some(StackRef
::from_ptr(chain
))
222 /// A builder used to construct an `X509`.
223 pub struct X509Builder(X509
);
226 /// Creates a new builder.
227 pub fn new() -> Result
<X509Builder
, ErrorStack
> {
230 cvt_p(ffi
::X509_new()).map(|p
| X509Builder(X509(p
)))
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(|_| ()) }
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(|_| ()) }
244 /// Sets the version of the certificate.
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(|_| ()) }
252 /// Sets the serial number of the certificate.
253 pub fn set_serial_number(&mut self, serial_number
: &Asn1IntegerRef
) -> Result
<(), ErrorStack
> {
255 cvt(ffi
::X509_set_serialNumber(
257 serial_number
.as_ptr(),
263 /// Sets the issuer name of the certificate.
264 pub fn set_issuer_name(&mut self, issuer_name
: &X509NameRef
) -> Result
<(), ErrorStack
> {
266 cvt(ffi
::X509_set_issuer_name(
268 issuer_name
.as_ptr(),
274 /// Sets the subject name of the certificate.
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.
280 /// use openssl::x509::{X509, X509NameBuilder};
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();
289 /// let mut x509 = openssl::x509::X509::builder().unwrap();
290 /// x509.set_subject_name(&x509_name).unwrap();
292 pub fn set_subject_name(&mut self, subject_name
: &X509NameRef
) -> Result
<(), ErrorStack
> {
294 cvt(ffi
::X509_set_subject_name(
296 subject_name
.as_ptr(),
302 /// Sets the public key associated with the certificate.
303 pub fn set_pubkey
<T
>(&mut self, key
: &PKeyRef
<T
>) -> Result
<(), ErrorStack
>
307 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
310 /// Returns a context object which is needed to create certain X509 extension values.
312 /// Set `issuer` to `None` if the certificate will be self-signed.
313 pub fn x509v3_context
<'a
>(
315 issuer
: Option
<&'a X509Ref
>,
316 conf
: Option
<&'a ConfRef
>,
317 ) -> X509v3Context
<'a
> {
319 let mut ctx
= mem
::zeroed();
321 let issuer
= match issuer
{
322 Some(issuer
) => issuer
.as_ptr(),
323 None
=> self.0.as_ptr(),
325 let subject
= self.0.as_ptr();
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());
340 X509v3Context(ctx
, PhantomData
)
344 /// Adds an X509 extension value to the certificate.
346 /// This works just as `append_extension` except it takes ownership of the `X509Extension`.
347 pub fn append_extension(&mut self, extension
: X509Extension
) -> Result
<(), ErrorStack
> {
348 self.append_extension2(&extension
)
351 /// Adds an X509 extension value to the certificate.
353 /// This corresponds to [`X509_add_ext`].
355 /// [`X509_add_ext`]: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext.html
356 pub fn append_extension2(&mut self, extension
: &X509ExtensionRef
) -> Result
<(), ErrorStack
> {
358 cvt(ffi
::X509_add_ext(self.0.as_ptr(), extension
.as_ptr(), -1))?
;
363 /// Signs the certificate with a private key.
364 pub fn sign
<T
>(&mut self, key
: &PKeyRef
<T
>, hash
: MessageDigest
) -> Result
<(), ErrorStack
>
368 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
371 /// Consumes the builder, returning the certificate.
372 pub fn build(self) -> X509
{
377 foreign_type_and_impl_send_sync
! {
378 type CType
= ffi
::X509
;
379 fn drop
= ffi
::X509_free
;
381 /// An `X509` public key certificate.
383 /// Reference to `X509`.
388 /// Returns this certificate's subject name.
390 /// This corresponds to [`X509_get_subject_name`].
392 /// [`X509_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html
393 pub fn subject_name(&self) -> &X509NameRef
{
395 let name
= ffi
::X509_get_subject_name(self.as_ptr());
396 assert
!(!name
.is_null());
397 X509NameRef
::from_ptr(name
)
401 /// Returns this certificate's issuer name.
403 /// This corresponds to [`X509_get_issuer_name`].
405 /// [`X509_get_issuer_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html
406 pub fn issuer_name(&self) -> &X509NameRef
{
408 let name
= ffi
::X509_get_issuer_name(self.as_ptr());
409 assert
!(!name
.is_null());
410 X509NameRef
::from_ptr(name
)
414 /// Returns this certificate's subject alternative name entries, if they exist.
416 /// This corresponds to [`X509_get_ext_d2i`] called with `NID_subject_alt_name`.
418 /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html
419 pub fn subject_alt_names(&self) -> Option
<Stack
<GeneralName
>> {
421 let stack
= ffi
::X509_get_ext_d2i(
423 ffi
::NID_subject_alt_name
,
430 Some(Stack
::from_ptr(stack
as *mut _
))
435 /// Returns this certificate's issuer alternative name entries, if they exist.
437 /// This corresponds to [`X509_get_ext_d2i`] called with `NID_issuer_alt_name`.
439 /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html
440 pub fn issuer_alt_names(&self) -> Option
<Stack
<GeneralName
>> {
442 let stack
= ffi
::X509_get_ext_d2i(
444 ffi
::NID_issuer_alt_name
,
451 Some(Stack
::from_ptr(stack
as *mut _
))
456 pub fn public_key(&self) -> Result
<PKey
<Public
>, ErrorStack
> {
458 let pkey
= cvt_p(ffi
::X509_get_pubkey(self.as_ptr()))?
;
459 Ok(PKey
::from_ptr(pkey
))
463 /// Returns a digest of the DER representation of the certificate.
465 /// This corresponds to [`X509_digest`].
467 /// [`X509_digest`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_digest.html
468 pub fn digest(&self, hash_type
: MessageDigest
) -> Result
<DigestBytes
, ErrorStack
> {
470 let mut digest
= DigestBytes
{
471 buf
: [0; ffi
::EVP_MAX_MD_SIZE
as usize],
472 len
: ffi
::EVP_MAX_MD_SIZE
as usize,
474 let mut len
= ffi
::EVP_MAX_MD_SIZE
;
475 cvt(ffi
::X509_digest(
478 digest
.buf
.as_mut_ptr() as *mut _
,
481 digest
.len
= len
as usize;
487 #[deprecated(since = "0.10.9", note = "renamed to digest")]
488 pub fn fingerprint(&self, hash_type
: MessageDigest
) -> Result
<Vec
<u8>, ErrorStack
> {
489 self.digest(hash_type
).map(|b
| b
.to_vec())
492 /// Returns the certificate's Not After validity period.
493 pub fn not_after(&self) -> &Asn1TimeRef
{
495 let date
= X509_getm_notAfter(self.as_ptr());
496 assert
!(!date
.is_null());
497 Asn1TimeRef
::from_ptr(date
)
501 /// Returns the certificate's Not Before validity period.
502 pub fn not_before(&self) -> &Asn1TimeRef
{
504 let date
= X509_getm_notBefore(self.as_ptr());
505 assert
!(!date
.is_null());
506 Asn1TimeRef
::from_ptr(date
)
510 /// Returns the certificate's signature
511 pub fn signature(&self) -> &Asn1BitStringRef
{
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 _
)
520 /// Returns the certificate's signature algorithm.
521 pub fn signature_algorithm(&self) -> &X509AlgorithmRef
{
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 _
)
530 /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
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)) }
536 /// Checks that this certificate issued `subject`.
537 pub fn issued(&self, subject
: &X509Ref
) -> X509VerifyResult
{
539 let r
= ffi
::X509_check_issued(self.as_ptr(), subject
.as_ptr());
540 X509VerifyResult
::from_raw(r
)
544 /// Check if the certificate is signed using the given public key.
546 /// Only the signature is checked: no other checks (such as certificate chain validity)
549 /// Returns `true` if verification succeeds.
551 /// This corresponds to [`X509_verify"].
553 /// [`X509_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify.html
554 pub fn verify
<T
>(&self, key
: &PKeyRef
<T
>) -> Result
<bool
, ErrorStack
>
558 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
561 /// Returns this certificate's serial number.
563 /// This corresponds to [`X509_get_serialNumber`].
565 /// [`X509_get_serialNumber`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_serialNumber.html
566 pub fn serial_number(&self) -> &Asn1IntegerRef
{
568 let r
= ffi
::X509_get_serialNumber(self.as_ptr());
569 assert
!(!r
.is_null());
570 Asn1IntegerRef
::from_ptr(r
)
575 /// Serializes the certificate into a PEM-encoded X509 structure.
577 /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
579 /// This corresponds to [`PEM_write_bio_X509`].
581 /// [`PEM_write_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509.html
583 ffi
::PEM_write_bio_X509
587 /// Serializes the certificate into a DER-encoded X509 structure.
589 /// This corresponds to [`i2d_X509`].
591 /// [`i2d_X509`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509.html
597 impl ToOwned
for X509Ref
{
600 fn to_owned(&self) -> X509
{
602 X509_up_ref(self.as_ptr());
603 X509
::from_ptr(self.as_ptr())
609 /// Returns a new builder.
610 pub fn builder() -> Result
<X509Builder
, ErrorStack
> {
615 /// Deserializes a PEM-encoded X509 structure.
617 /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
619 /// This corresponds to [`PEM_read_bio_X509`].
621 /// [`PEM_read_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509.html
624 ffi
::PEM_read_bio_X509
628 /// Deserializes a DER-encoded X509 structure.
630 /// This corresponds to [`d2i_X509`].
632 /// [`d2i_X509`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html
638 /// Deserializes a list of PEM-formatted certificates.
639 pub fn stack_from_pem(pem
: &[u8]) -> Result
<Vec
<X509
>, ErrorStack
> {
642 let bio
= MemBioSlice
::new(pem
)?
;
644 let mut certs
= vec
![];
647 ffi
::PEM_read_bio_X509(bio
.as_ptr(), ptr
::null_mut(), None
, ptr
::null_mut());
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
653 ffi
::ERR_clear_error();
657 return Err(ErrorStack
::get());
668 impl Clone
for X509
{
669 fn clone(&self) -> X509
{
670 X509Ref
::to_owned(self)
674 impl fmt
::Debug
for X509
{
675 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(),
681 Err(_
) => "".to_string(),
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
);
691 debug_struct
.field("not_before", &self.not_before());
692 debug_struct
.field("not_after", &self.not_after());
694 if let Ok(public_key
) = &self.public_key() {
695 debug_struct
.field("public_key", public_key
);
697 // TODO: Print extensions once they are supported on the X509 struct.
699 debug_struct
.finish()
703 impl AsRef
<X509Ref
> for X509Ref
{
704 fn as_ref(&self) -> &X509Ref
{
709 impl Stackable
for X509
{
710 type StackType
= ffi
::stack_st_X509
;
713 /// A context object required to construct certain `X509` extension values.
714 pub struct X509v3Context
<'a
>(ffi
::X509V3_CTX
, PhantomData
<(&'a X509Ref
, &'a ConfRef
)>);
716 impl<'a
> X509v3Context
<'a
> {
717 pub fn as_ptr(&self) -> *mut ffi
::X509V3_CTX
{
718 &self.0 as *const _
as *mut _
722 foreign_type_and_impl_send_sync
! {
723 type CType
= ffi
::X509_EXTENSION
;
724 fn drop
= ffi
::X509_EXTENSION_free
;
726 /// Permit additional fields to be added to an `X509` v3 certificate.
727 pub struct X509Extension
;
728 /// Reference to `X509Extension`.
729 pub struct X509ExtensionRef
;
732 impl Stackable
for X509Extension
{
733 type StackType
= ffi
::stack_st_X509_EXTENSION
;
737 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
738 /// names and their value formats.
740 /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
743 /// See the extension module for builder types which will construct certain common extensions.
745 conf
: Option
<&ConfRef
>,
746 context
: Option
<&X509v3Context
>,
749 ) -> Result
<X509Extension
, ErrorStack
> {
750 let name
= CString
::new(name
).unwrap();
751 let value
= CString
::new(value
).unwrap();
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 _
;
759 cvt_p(ffi
::X509V3_EXT_nconf(conf
, context
, name
, value
)).map(X509Extension
)
763 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
764 /// extensions and their value formats.
766 /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
769 /// See the extension module for builder types which will construct certain common extensions.
771 conf
: Option
<&ConfRef
>,
772 context
: Option
<&X509v3Context
>,
775 ) -> Result
<X509Extension
, ErrorStack
> {
776 let value
= CString
::new(value
).unwrap();
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 _
;
784 cvt_p(ffi
::X509V3_EXT_nconf_nid(conf
, context
, name
, value
)).map(X509Extension
)
789 /// A builder used to construct an `X509Name`.
790 pub struct X509NameBuilder(X509Name
);
792 impl X509NameBuilder
{
793 /// Creates a new builder.
794 pub fn new() -> Result
<X509NameBuilder
, ErrorStack
> {
797 cvt_p(ffi
::X509_NAME_new()).map(|p
| X509NameBuilder(X509Name(p
)))
801 /// Add a field entry by str.
803 /// This corresponds to [`X509_NAME_add_entry_by_txt`].
805 /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html
806 pub fn append_entry_by_text(&mut self, field
: &str, value
: &str) -> Result
<(), ErrorStack
> {
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(
812 field
.as_ptr() as *mut _
,
815 value
.len() as c_int
,
823 /// Add a field entry by NID.
825 /// This corresponds to [`X509_NAME_add_entry_by_NID`].
827 /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html
828 pub fn append_entry_by_nid(&mut self, field
: Nid
, value
: &str) -> Result
<(), ErrorStack
> {
830 assert
!(value
.len() <= c_int
::max_value() as usize);
831 cvt(ffi
::X509_NAME_add_entry_by_NID(
835 value
.as_ptr() as *mut _
,
836 value
.len() as c_int
,
844 /// Return an `X509Name`.
845 pub fn build(self) -> X509Name
{
850 foreign_type_and_impl_send_sync
! {
851 type CType
= ffi
::X509_NAME
;
852 fn drop
= ffi
::X509_NAME_free
;
854 /// The names of an `X509` certificate.
856 /// Reference to `X509Name`.
857 pub struct X509NameRef
;
861 /// Returns a new builder.
862 pub fn builder() -> Result
<X509NameBuilder
, ErrorStack
> {
863 X509NameBuilder
::new()
866 /// Loads subject names from a file containing PEM-formatted certificates.
868 /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`.
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)) }
875 impl Stackable
for X509Name
{
876 type StackType
= ffi
::stack_st_X509_NAME
;
880 /// Returns the name entries by the nid.
881 pub fn entries_by_nid(&self, nid
: Nid
) -> X509NameEntries
<'_
> {
889 /// Returns an iterator over all `X509NameEntry` values
890 pub fn entries(&self) -> X509NameEntries
<'_
> {
899 impl fmt
::Debug
for X509NameRef
{
900 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
901 formatter
.debug_list().entries(self.entries()).finish()
905 /// A type to destructure and examine an `X509Name`.
906 pub struct X509NameEntries
<'a
> {
907 name
: &'a X509NameRef
,
912 impl<'a
> Iterator
for X509NameEntries
<'a
> {
913 type Item
= &'a X509NameEntryRef
;
915 fn next(&mut self) -> Option
<&'a X509NameEntryRef
> {
919 // There is a `Nid` specified to search for
921 ffi
::X509_NAME_get_index_by_NID(self.name
.as_ptr(), nid
.as_raw(), self.loc
);
927 // Iterate over all `Nid`s
929 if self.loc
>= ffi
::X509_NAME_entry_count(self.name
.as_ptr()) {
935 let entry
= ffi
::X509_NAME_get_entry(self.name
.as_ptr(), self.loc
);
936 assert
!(!entry
.is_null());
938 Some(X509NameEntryRef
::from_ptr(entry
))
943 foreign_type_and_impl_send_sync
! {
944 type CType
= ffi
::X509_NAME_ENTRY
;
945 fn drop
= ffi
::X509_NAME_ENTRY_free
;
947 /// A name entry associated with a `X509Name`.
948 pub struct X509NameEntry
;
949 /// Reference to `X509NameEntry`.
950 pub struct X509NameEntryRef
;
953 impl X509NameEntryRef
{
954 /// Returns the field value of an `X509NameEntry`.
956 /// This corresponds to [`X509_NAME_ENTRY_get_data`].
958 /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html
959 pub fn data(&self) -> &Asn1StringRef
{
961 let data
= ffi
::X509_NAME_ENTRY_get_data(self.as_ptr());
962 Asn1StringRef
::from_ptr(data
)
966 /// Returns the `Asn1Object` value of an `X509NameEntry`.
967 /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
969 /// This corresponds to [`X509_NAME_ENTRY_get_object`].
971 /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html
972 pub fn object(&self) -> &Asn1ObjectRef
{
974 let object
= ffi
::X509_NAME_ENTRY_get_object(self.as_ptr());
975 Asn1ObjectRef
::from_ptr(object
)
980 impl fmt
::Debug
for X509NameEntryRef
{
981 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
982 formatter
.write_fmt(format_args
!("{:?} = {:?}", self.object(), self.data()))
986 /// A builder used to construct an `X509Req`.
987 pub struct X509ReqBuilder(X509Req
);
989 impl X509ReqBuilder
{
990 /// Returns a builder for a certificate request.
992 /// This corresponds to [`X509_REQ_new`].
994 ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html
995 pub fn new() -> Result
<X509ReqBuilder
, ErrorStack
> {
998 cvt_p(ffi
::X509_REQ_new()).map(|p
| X509ReqBuilder(X509Req(p
)))
1002 /// Set the numerical value of the version field.
1004 /// This corresponds to [`X509_REQ_set_version`].
1006 ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html
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(|_| ()) }
1011 /// Set the issuer name.
1013 /// This corresponds to [`X509_REQ_set_subject_name`].
1015 /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_subject_name.html
1016 pub fn set_subject_name(&mut self, subject_name
: &X509NameRef
) -> Result
<(), ErrorStack
> {
1018 cvt(ffi
::X509_REQ_set_subject_name(
1020 subject_name
.as_ptr(),
1026 /// Set the public key.
1028 /// This corresponds to [`X509_REQ_set_pubkey`].
1030 /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_pubkey.html
1031 pub fn set_pubkey
<T
>(&mut self, key
: &PKeyRef
<T
>) -> Result
<(), ErrorStack
>
1035 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1038 /// Return an `X509v3Context`. This context object can be used to construct
1039 /// certain `X509` extensions.
1040 pub fn x509v3_context
<'a
>(&'a
self, conf
: Option
<&'a ConfRef
>) -> X509v3Context
<'a
> {
1042 let mut ctx
= mem
::zeroed();
1044 ffi
::X509V3_set_ctx(
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());
1058 X509v3Context(ctx
, PhantomData
)
1062 /// Permits any number of extension fields to be added to the certificate.
1063 pub fn add_extensions(
1065 extensions
: &StackRef
<X509Extension
>,
1066 ) -> Result
<(), ErrorStack
> {
1068 cvt(ffi
::X509_REQ_add_extensions(
1070 extensions
.as_ptr(),
1076 /// Sign the request using a private key.
1078 /// This corresponds to [`X509_REQ_sign`].
1080 /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html
1081 pub fn sign
<T
>(&mut self, key
: &PKeyRef
<T
>, hash
: MessageDigest
) -> Result
<(), ErrorStack
>
1086 cvt(ffi
::X509_REQ_sign(
1095 /// Returns the `X509Req`.
1096 pub fn build(self) -> X509Req
{
1101 foreign_type_and_impl_send_sync
! {
1102 type CType
= ffi
::X509_REQ
;
1103 fn drop
= ffi
::X509_REQ_free
;
1105 /// An `X509` certificate request.
1107 /// Reference to `X509Req`.
1108 pub struct X509ReqRef
;
1112 /// A builder for `X509Req`.
1113 pub fn builder() -> Result
<X509ReqBuilder
, ErrorStack
> {
1114 X509ReqBuilder
::new()
1118 /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1120 /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1122 /// This corresponds to [`PEM_read_bio_X509_REQ`].
1124 /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html
1127 ffi
::PEM_read_bio_X509_REQ
1131 /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1133 /// This corresponds to [`d2i_X509_REQ`].
1135 /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html
1144 /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1146 /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1148 /// This corresponds to [`PEM_write_bio_X509_REQ`].
1150 /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html
1152 ffi
::PEM_write_bio_X509_REQ
1156 /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1158 /// This corresponds to [`i2d_X509_REQ`].
1160 /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html
1165 /// Returns the numerical value of the version field of the certificate request.
1167 /// This corresponds to [`X509_REQ_get_version`]
1169 /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html
1170 pub fn version(&self) -> i32 {
1171 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1174 /// Returns the subject name of the certificate request.
1176 /// This corresponds to [`X509_REQ_get_subject_name`]
1178 /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html
1179 pub fn subject_name(&self) -> &X509NameRef
{
1181 let name
= X509_REQ_get_subject_name(self.as_ptr());
1182 assert
!(!name
.is_null());
1183 X509NameRef
::from_ptr(name
)
1187 /// Returns the public key of the certificate request.
1189 /// This corresponds to [`X509_REQ_get_pubkey"]
1191 /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html
1192 pub fn public_key(&self) -> Result
<PKey
<Public
>, ErrorStack
> {
1194 let key
= cvt_p(ffi
::X509_REQ_get_pubkey(self.as_ptr()))?
;
1195 Ok(PKey
::from_ptr(key
))
1199 /// Check if the certificate request is signed using the given public key.
1201 /// Returns `true` if verification succeeds.
1203 /// This corresponds to [`X509_REQ_verify"].
1205 /// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html
1206 pub fn verify
<T
>(&self, key
: &PKeyRef
<T
>) -> Result
<bool
, ErrorStack
>
1210 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1213 /// Returns the extensions of the certificate request.
1215 /// This corresponds to [`X509_REQ_get_extensions"]
1216 pub fn extensions(&self) -> Result
<Stack
<X509Extension
>, ErrorStack
> {
1218 let extensions
= cvt_p(ffi
::X509_REQ_get_extensions(self.as_ptr()))?
;
1219 Ok(Stack
::from_ptr(extensions
))
1224 /// The result of peer certificate verification.
1225 #[derive(Copy, Clone, PartialEq, Eq)]
1226 pub struct X509VerifyResult(c_int
);
1228 impl fmt
::Debug
for X509VerifyResult
{
1229 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())
1237 impl fmt
::Display
for X509VerifyResult
{
1238 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
1239 fmt
.write_str(self.error_string())
1243 impl Error
for X509VerifyResult {}
1245 impl X509VerifyResult
{
1246 /// Creates an `X509VerifyResult` from a raw error number.
1250 /// Some methods on `X509VerifyResult` are not thread safe if the error
1251 /// number is invalid.
1252 pub unsafe fn from_raw(err
: c_int
) -> X509VerifyResult
{
1253 X509VerifyResult(err
)
1256 /// Return the integer representation of an `X509VerifyResult`.
1257 #[allow(clippy::trivially_copy_pass_by_ref)]
1258 pub fn as_raw(&self) -> c_int
{
1262 /// Return a human readable error string from the verification error.
1264 /// This corresponds to [`X509_verify_cert_error_string`].
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)]
1268 pub fn error_string(&self) -> &'
static str {
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()
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
);
1284 foreign_type_and_impl_send_sync
! {
1285 type CType
= ffi
::GENERAL_NAME
;
1286 fn drop
= ffi
::GENERAL_NAME_free
;
1288 /// An `X509` certificate alternative names.
1289 pub struct GeneralName
;
1290 /// Reference to `GeneralName`.
1291 pub struct GeneralNameRef
;
1294 impl GeneralNameRef
{
1295 fn ia5_string(&self, ffi_type
: c_int
) -> Option
<&str> {
1297 if (*self.as_ptr()).type_
!= ffi_type
{
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 _
);
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()
1312 /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
1313 pub fn email(&self) -> Option
<&str> {
1314 self.ia5_string(ffi
::GEN_EMAIL
)
1317 /// Returns the contents of this `GeneralName` if it is a `dNSName`.
1318 pub fn dnsname(&self) -> Option
<&str> {
1319 self.ia5_string(ffi
::GEN_DNS
)
1322 /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
1323 pub fn uri(&self) -> Option
<&str> {
1324 self.ia5_string(ffi
::GEN_URI
)
1327 /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
1328 pub fn ipaddress(&self) -> Option
<&[u8]> {
1330 if (*self.as_ptr()).type_
!= ffi
::GEN_IPADD
{
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 _
);
1337 Some(slice
::from_raw_parts(ptr
as *const u8, len
as usize))
1342 impl fmt
::Debug
for GeneralNameRef
{
1343 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
)
1354 formatter
.write_str("(empty)")
1359 impl Stackable
for GeneralName
{
1360 type StackType
= ffi
::stack_st_GENERAL_NAME
;
1363 foreign_type_and_impl_send_sync
! {
1364 type CType
= ffi
::X509_ALGOR
;
1365 fn drop
= ffi
::X509_ALGOR_free
;
1367 /// An `X509` certificate signature algorithm.
1368 pub struct X509Algorithm
;
1369 /// Reference to `X509Algorithm`.
1370 pub struct X509AlgorithmRef
;
1373 impl X509AlgorithmRef
{
1374 /// Returns the ASN.1 OID of this algorithm.
1375 pub fn object(&self) -> &Asn1ObjectRef
{
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 _
)
1385 foreign_type_and_impl_send_sync
! {
1386 type CType
= ffi
::X509_OBJECT
;
1387 fn drop
= X509_OBJECT_free
;
1389 /// An `X509` or an X509 certificate revocation list.
1390 pub struct X509Object
;
1391 /// Reference to `X509Object`
1392 pub struct X509ObjectRef
;
1395 impl X509ObjectRef
{
1396 pub fn x509(&self) -> Option
<&X509Ref
> {
1398 let ptr
= X509_OBJECT_get0_X509(self.as_ptr());
1402 Some(X509Ref
::from_ptr(ptr
))
1408 impl Stackable
for X509Object
{
1409 type StackType
= ffi
::stack_st_X509_OBJECT
;
1413 if #[cfg(any(ossl110, libressl273))] {
1414 use ffi
::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature}
;
1417 unsafe fn X509_getm_notAfter(x
: *mut ffi
::X509
) -> *mut ffi
::ASN1_TIME
{
1418 (*(*(*x
).cert_info
).validity
).notAfter
1422 unsafe fn X509_getm_notBefore(x
: *mut ffi
::X509
) -> *mut ffi
::ASN1_TIME
{
1423 (*(*(*x
).cert_info
).validity
).notBefore
1427 unsafe fn X509_up_ref(x
: *mut ffi
::X509
) {
1428 ffi
::CRYPTO_add_lock(
1429 &mut (*x
).references
,
1431 ffi
::CRYPTO_LOCK_X509
,
1432 "mod.rs\0".as_ptr() as *const _
,
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
,
1443 if !psig
.is_null() {
1444 *psig
= (*x
).signature
;
1446 if !palg
.is_null() {
1447 *palg
= (*x
).sig_alg
;
1454 if #[cfg(ossl110)] {
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
,
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
,
1468 unsafe fn X509_REQ_get_version(x
: *mut ffi
::X509_REQ
) -> ::libc
::c_long
{
1469 ffi
::ASN1_INTEGER_get((*(*x
).req_info
).version
)
1473 unsafe fn X509_REQ_get_subject_name(x
: *mut ffi
::X509_REQ
) -> *mut ::ffi
::X509_NAME
{
1474 (*(*x
).req_info
).subject
1478 unsafe fn X509_ALGOR_get0(
1479 paobj
: *mut *const ffi
::ASN1_OBJECT
,
1481 pval
: *mut *mut ::libc
::c_void
,
1482 alg
: *const ffi
::X509_ALGOR
,
1484 if !paobj
.is_null() {
1485 *paobj
= (*alg
).algorithm
;
1487 assert
!(pptype
.is_null());
1488 assert
!(pval
.is_null());
1494 if #[cfg(any(ossl110, libressl270))] {
1495 use ffi
::X509_OBJECT_get0_X509
;
1498 unsafe fn X509_OBJECT_get0_X509(x
: *mut ffi
::X509_OBJECT
) -> *mut ffi
::X509
{
1499 if (*x
).type_
== ffi
::X509_LU_X509
{
1509 if #[cfg(ossl110)] {
1510 use ffi
::X509_OBJECT_free
;
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
);