192f3ab15Sopenharmony_ci//! Describe a context in which to verify an `X509` certificate.
292f3ab15Sopenharmony_ci//!
392f3ab15Sopenharmony_ci//! The `X509` certificate store holds trusted CA certificates used to verify
492f3ab15Sopenharmony_ci//! peer certificates.
592f3ab15Sopenharmony_ci//!
692f3ab15Sopenharmony_ci//! # Example
792f3ab15Sopenharmony_ci//!
892f3ab15Sopenharmony_ci//! ```rust
992f3ab15Sopenharmony_ci//! use openssl::x509::store::{X509StoreBuilder, X509Store};
1092f3ab15Sopenharmony_ci//! use openssl::x509::{X509, X509Name};
1192f3ab15Sopenharmony_ci//! use openssl::asn1::Asn1Time;
1292f3ab15Sopenharmony_ci//! use openssl::pkey::PKey;
1392f3ab15Sopenharmony_ci//! use openssl::hash::MessageDigest;
1492f3ab15Sopenharmony_ci//! use openssl::rsa::Rsa;
1592f3ab15Sopenharmony_ci//! use openssl::nid::Nid;
1692f3ab15Sopenharmony_ci//!
1792f3ab15Sopenharmony_ci//! let rsa = Rsa::generate(2048).unwrap();
1892f3ab15Sopenharmony_ci//! let pkey = PKey::from_rsa(rsa).unwrap();
1992f3ab15Sopenharmony_ci//!
2092f3ab15Sopenharmony_ci//! let mut name = X509Name::builder().unwrap();
2192f3ab15Sopenharmony_ci//! name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap();
2292f3ab15Sopenharmony_ci//! let name = name.build();
2392f3ab15Sopenharmony_ci//!
2492f3ab15Sopenharmony_ci//! // Sep 27th, 2016
2592f3ab15Sopenharmony_ci//! let sample_time = Asn1Time::from_unix(1474934400).unwrap();
2692f3ab15Sopenharmony_ci//!
2792f3ab15Sopenharmony_ci//! let mut builder = X509::builder().unwrap();
2892f3ab15Sopenharmony_ci//! builder.set_version(2).unwrap();
2992f3ab15Sopenharmony_ci//! builder.set_subject_name(&name).unwrap();
3092f3ab15Sopenharmony_ci//! builder.set_issuer_name(&name).unwrap();
3192f3ab15Sopenharmony_ci//! builder.set_pubkey(&pkey).unwrap();
3292f3ab15Sopenharmony_ci//! builder.set_not_before(&sample_time);
3392f3ab15Sopenharmony_ci//! builder.set_not_after(&sample_time);
3492f3ab15Sopenharmony_ci//! builder.sign(&pkey, MessageDigest::sha256()).unwrap();
3592f3ab15Sopenharmony_ci//!
3692f3ab15Sopenharmony_ci//! let certificate: X509 = builder.build();
3792f3ab15Sopenharmony_ci//!
3892f3ab15Sopenharmony_ci//! let mut builder = X509StoreBuilder::new().unwrap();
3992f3ab15Sopenharmony_ci//! let _ = builder.add_cert(certificate);
4092f3ab15Sopenharmony_ci//!
4192f3ab15Sopenharmony_ci//! let store: X509Store = builder.build();
4292f3ab15Sopenharmony_ci//! ```
4392f3ab15Sopenharmony_ci
4492f3ab15Sopenharmony_ciuse cfg_if::cfg_if;
4592f3ab15Sopenharmony_ciuse foreign_types::{ForeignType, ForeignTypeRef};
4692f3ab15Sopenharmony_ciuse std::mem;
4792f3ab15Sopenharmony_ci
4892f3ab15Sopenharmony_ciuse crate::error::ErrorStack;
4992f3ab15Sopenharmony_ci#[cfg(not(boringssl))]
5092f3ab15Sopenharmony_ciuse crate::ssl::SslFiletype;
5192f3ab15Sopenharmony_ciuse crate::stack::{Stack, StackRef};
5292f3ab15Sopenharmony_ci#[cfg(any(ossl102, libressl261))]
5392f3ab15Sopenharmony_ciuse crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef};
5492f3ab15Sopenharmony_ciuse crate::x509::{X509Object, X509PurposeId, X509};
5592f3ab15Sopenharmony_ciuse crate::{cvt, cvt_p};
5692f3ab15Sopenharmony_ciuse openssl_macros::corresponds;
5792f3ab15Sopenharmony_ci#[cfg(not(boringssl))]
5892f3ab15Sopenharmony_ciuse std::ffi::CString;
5992f3ab15Sopenharmony_ci#[cfg(not(boringssl))]
6092f3ab15Sopenharmony_ciuse std::path::Path;
6192f3ab15Sopenharmony_ci
6292f3ab15Sopenharmony_ciforeign_type_and_impl_send_sync! {
6392f3ab15Sopenharmony_ci    type CType = ffi::X509_STORE;
6492f3ab15Sopenharmony_ci    fn drop = ffi::X509_STORE_free;
6592f3ab15Sopenharmony_ci
6692f3ab15Sopenharmony_ci    /// A builder type used to construct an `X509Store`.
6792f3ab15Sopenharmony_ci    pub struct X509StoreBuilder;
6892f3ab15Sopenharmony_ci    /// A reference to an [`X509StoreBuilder`].
6992f3ab15Sopenharmony_ci    pub struct X509StoreBuilderRef;
7092f3ab15Sopenharmony_ci}
7192f3ab15Sopenharmony_ci
7292f3ab15Sopenharmony_ciimpl X509StoreBuilder {
7392f3ab15Sopenharmony_ci    /// Returns a builder for a certificate store.
7492f3ab15Sopenharmony_ci    ///
7592f3ab15Sopenharmony_ci    /// The store is initially empty.
7692f3ab15Sopenharmony_ci    #[corresponds(X509_STORE_new)]
7792f3ab15Sopenharmony_ci    pub fn new() -> Result<X509StoreBuilder, ErrorStack> {
7892f3ab15Sopenharmony_ci        unsafe {
7992f3ab15Sopenharmony_ci            ffi::init();
8092f3ab15Sopenharmony_ci
8192f3ab15Sopenharmony_ci            cvt_p(ffi::X509_STORE_new()).map(X509StoreBuilder)
8292f3ab15Sopenharmony_ci        }
8392f3ab15Sopenharmony_ci    }
8492f3ab15Sopenharmony_ci
8592f3ab15Sopenharmony_ci    /// Constructs the `X509Store`.
8692f3ab15Sopenharmony_ci    pub fn build(self) -> X509Store {
8792f3ab15Sopenharmony_ci        let store = X509Store(self.0);
8892f3ab15Sopenharmony_ci        mem::forget(self);
8992f3ab15Sopenharmony_ci        store
9092f3ab15Sopenharmony_ci    }
9192f3ab15Sopenharmony_ci}
9292f3ab15Sopenharmony_ci
9392f3ab15Sopenharmony_ciimpl X509StoreBuilderRef {
9492f3ab15Sopenharmony_ci    /// Adds a certificate to the certificate store.
9592f3ab15Sopenharmony_ci    // FIXME should take an &X509Ref
9692f3ab15Sopenharmony_ci    #[corresponds(X509_STORE_add_cert)]
9792f3ab15Sopenharmony_ci    pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
9892f3ab15Sopenharmony_ci        unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
9992f3ab15Sopenharmony_ci    }
10092f3ab15Sopenharmony_ci
10192f3ab15Sopenharmony_ci    /// Load certificates from their default locations.
10292f3ab15Sopenharmony_ci    ///
10392f3ab15Sopenharmony_ci    /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
10492f3ab15Sopenharmony_ci    /// environment variables if present, or defaults specified at OpenSSL
10592f3ab15Sopenharmony_ci    /// build time otherwise.
10692f3ab15Sopenharmony_ci    #[corresponds(X509_STORE_set_default_paths)]
10792f3ab15Sopenharmony_ci    pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> {
10892f3ab15Sopenharmony_ci        unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) }
10992f3ab15Sopenharmony_ci    }
11092f3ab15Sopenharmony_ci
11192f3ab15Sopenharmony_ci    /// Adds a lookup method to the store.
11292f3ab15Sopenharmony_ci    #[corresponds(X509_STORE_add_lookup)]
11392f3ab15Sopenharmony_ci    pub fn add_lookup<T>(
11492f3ab15Sopenharmony_ci        &mut self,
11592f3ab15Sopenharmony_ci        method: &'static X509LookupMethodRef<T>,
11692f3ab15Sopenharmony_ci    ) -> Result<&mut X509LookupRef<T>, ErrorStack> {
11792f3ab15Sopenharmony_ci        let lookup = unsafe { ffi::X509_STORE_add_lookup(self.as_ptr(), method.as_ptr()) };
11892f3ab15Sopenharmony_ci        cvt_p(lookup).map(|ptr| unsafe { X509LookupRef::from_ptr_mut(ptr) })
11992f3ab15Sopenharmony_ci    }
12092f3ab15Sopenharmony_ci
12192f3ab15Sopenharmony_ci    /// Sets certificate chain validation related flags.
12292f3ab15Sopenharmony_ci    #[corresponds(X509_STORE_set_flags)]
12392f3ab15Sopenharmony_ci    #[cfg(any(ossl102, libressl261))]
12492f3ab15Sopenharmony_ci    pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
12592f3ab15Sopenharmony_ci        unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) }
12692f3ab15Sopenharmony_ci    }
12792f3ab15Sopenharmony_ci
12892f3ab15Sopenharmony_ci    /// Sets the certificate purpose.
12992f3ab15Sopenharmony_ci    /// The purpose value can be obtained by `X509PurposeRef::get_by_sname()`
13092f3ab15Sopenharmony_ci    #[corresponds(X509_STORE_set_purpose)]
13192f3ab15Sopenharmony_ci    pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> {
13292f3ab15Sopenharmony_ci        unsafe { cvt(ffi::X509_STORE_set_purpose(self.as_ptr(), purpose.as_raw())).map(|_| ()) }
13392f3ab15Sopenharmony_ci    }
13492f3ab15Sopenharmony_ci
13592f3ab15Sopenharmony_ci    /// Sets certificate chain validation related parameters.
13692f3ab15Sopenharmony_ci    #[corresponds[X509_STORE_set1_param]]
13792f3ab15Sopenharmony_ci    #[cfg(any(ossl102, libressl261))]
13892f3ab15Sopenharmony_ci    pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> {
13992f3ab15Sopenharmony_ci        unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())).map(|_| ()) }
14092f3ab15Sopenharmony_ci    }
14192f3ab15Sopenharmony_ci}
14292f3ab15Sopenharmony_ci
14392f3ab15Sopenharmony_cigeneric_foreign_type_and_impl_send_sync! {
14492f3ab15Sopenharmony_ci    type CType = ffi::X509_LOOKUP;
14592f3ab15Sopenharmony_ci    fn drop = ffi::X509_LOOKUP_free;
14692f3ab15Sopenharmony_ci
14792f3ab15Sopenharmony_ci    /// Information used by an `X509Store` to look up certificates and CRLs.
14892f3ab15Sopenharmony_ci    pub struct X509Lookup<T>;
14992f3ab15Sopenharmony_ci    /// A reference to an [`X509Lookup`].
15092f3ab15Sopenharmony_ci    pub struct X509LookupRef<T>;
15192f3ab15Sopenharmony_ci}
15292f3ab15Sopenharmony_ci
15392f3ab15Sopenharmony_ci/// Marker type corresponding to the [`X509_LOOKUP_hash_dir`] lookup method.
15492f3ab15Sopenharmony_ci///
15592f3ab15Sopenharmony_ci/// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/manmaster/crypto/X509_LOOKUP_hash_dir.html
15692f3ab15Sopenharmony_ci// FIXME should be an enum
15792f3ab15Sopenharmony_cipub struct HashDir;
15892f3ab15Sopenharmony_ci
15992f3ab15Sopenharmony_ciimpl X509Lookup<HashDir> {
16092f3ab15Sopenharmony_ci    /// Lookup method that loads certificates and CRLs on demand and caches
16192f3ab15Sopenharmony_ci    /// them in memory once they are loaded. It also checks for newer CRLs upon
16292f3ab15Sopenharmony_ci    /// each lookup, so that newer CRLs are used as soon as they appear in the
16392f3ab15Sopenharmony_ci    /// directory.
16492f3ab15Sopenharmony_ci    #[corresponds(X509_LOOKUP_hash_dir)]
16592f3ab15Sopenharmony_ci    pub fn hash_dir() -> &'static X509LookupMethodRef<HashDir> {
16692f3ab15Sopenharmony_ci        unsafe { X509LookupMethodRef::from_ptr(ffi::X509_LOOKUP_hash_dir()) }
16792f3ab15Sopenharmony_ci    }
16892f3ab15Sopenharmony_ci}
16992f3ab15Sopenharmony_ci
17092f3ab15Sopenharmony_ci#[cfg(not(boringssl))]
17192f3ab15Sopenharmony_ciimpl X509LookupRef<HashDir> {
17292f3ab15Sopenharmony_ci    /// Specifies a directory from which certificates and CRLs will be loaded
17392f3ab15Sopenharmony_ci    /// on-demand. Must be used with `X509Lookup::hash_dir`.
17492f3ab15Sopenharmony_ci    #[corresponds(X509_LOOKUP_add_dir)]
17592f3ab15Sopenharmony_ci    pub fn add_dir(&mut self, name: &str, file_type: SslFiletype) -> Result<(), ErrorStack> {
17692f3ab15Sopenharmony_ci        let name = CString::new(name).unwrap();
17792f3ab15Sopenharmony_ci        unsafe {
17892f3ab15Sopenharmony_ci            cvt(ffi::X509_LOOKUP_add_dir(
17992f3ab15Sopenharmony_ci                self.as_ptr(),
18092f3ab15Sopenharmony_ci                name.as_ptr(),
18192f3ab15Sopenharmony_ci                file_type.as_raw(),
18292f3ab15Sopenharmony_ci            ))
18392f3ab15Sopenharmony_ci            .map(|_| ())
18492f3ab15Sopenharmony_ci        }
18592f3ab15Sopenharmony_ci    }
18692f3ab15Sopenharmony_ci}
18792f3ab15Sopenharmony_ci
18892f3ab15Sopenharmony_ci/// Marker type corresponding to the [`X509_LOOKUP_file`] lookup method.
18992f3ab15Sopenharmony_ci///
19092f3ab15Sopenharmony_ci/// [`X509_LOOKUP_file`]: https://www.openssl.org/docs/man1.1.1/man3/X509_LOOKUP_file.html
19192f3ab15Sopenharmony_cipub struct File;
19292f3ab15Sopenharmony_ci
19392f3ab15Sopenharmony_ciimpl X509Lookup<File> {
19492f3ab15Sopenharmony_ci    /// Lookup method loads all the certificates or CRLs present in a file
19592f3ab15Sopenharmony_ci    /// into memory at the time the file is added as a lookup source.
19692f3ab15Sopenharmony_ci    #[corresponds(X509_LOOKUP_file)]
19792f3ab15Sopenharmony_ci    pub fn file() -> &'static X509LookupMethodRef<File> {
19892f3ab15Sopenharmony_ci        unsafe { X509LookupMethodRef::from_ptr(ffi::X509_LOOKUP_file()) }
19992f3ab15Sopenharmony_ci    }
20092f3ab15Sopenharmony_ci}
20192f3ab15Sopenharmony_ci
20292f3ab15Sopenharmony_ci#[cfg(not(boringssl))]
20392f3ab15Sopenharmony_ciimpl X509LookupRef<File> {
20492f3ab15Sopenharmony_ci    /// Specifies a file from which certificates will be loaded
20592f3ab15Sopenharmony_ci    #[corresponds(X509_load_cert_file)]
20692f3ab15Sopenharmony_ci    // FIXME should return 'Result<i32, ErrorStack' like load_crl_file
20792f3ab15Sopenharmony_ci    pub fn load_cert_file<P: AsRef<Path>>(
20892f3ab15Sopenharmony_ci        &mut self,
20992f3ab15Sopenharmony_ci        file: P,
21092f3ab15Sopenharmony_ci        file_type: SslFiletype,
21192f3ab15Sopenharmony_ci    ) -> Result<(), ErrorStack> {
21292f3ab15Sopenharmony_ci        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
21392f3ab15Sopenharmony_ci        unsafe {
21492f3ab15Sopenharmony_ci            cvt(ffi::X509_load_cert_file(
21592f3ab15Sopenharmony_ci                self.as_ptr(),
21692f3ab15Sopenharmony_ci                file.as_ptr(),
21792f3ab15Sopenharmony_ci                file_type.as_raw(),
21892f3ab15Sopenharmony_ci            ))
21992f3ab15Sopenharmony_ci            .map(|_| ())
22092f3ab15Sopenharmony_ci        }
22192f3ab15Sopenharmony_ci    }
22292f3ab15Sopenharmony_ci
22392f3ab15Sopenharmony_ci    /// Specifies a file from which certificate revocation lists will be loaded
22492f3ab15Sopenharmony_ci    #[corresponds(X509_load_crl_file)]
22592f3ab15Sopenharmony_ci    pub fn load_crl_file<P: AsRef<Path>>(
22692f3ab15Sopenharmony_ci        &mut self,
22792f3ab15Sopenharmony_ci        file: P,
22892f3ab15Sopenharmony_ci        file_type: SslFiletype,
22992f3ab15Sopenharmony_ci    ) -> Result<i32, ErrorStack> {
23092f3ab15Sopenharmony_ci        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
23192f3ab15Sopenharmony_ci        unsafe {
23292f3ab15Sopenharmony_ci            cvt(ffi::X509_load_crl_file(
23392f3ab15Sopenharmony_ci                self.as_ptr(),
23492f3ab15Sopenharmony_ci                file.as_ptr(),
23592f3ab15Sopenharmony_ci                file_type.as_raw(),
23692f3ab15Sopenharmony_ci            ))
23792f3ab15Sopenharmony_ci        }
23892f3ab15Sopenharmony_ci    }
23992f3ab15Sopenharmony_ci}
24092f3ab15Sopenharmony_ci
24192f3ab15Sopenharmony_cigeneric_foreign_type_and_impl_send_sync! {
24292f3ab15Sopenharmony_ci    type CType = ffi::X509_LOOKUP_METHOD;
24392f3ab15Sopenharmony_ci    fn drop = X509_LOOKUP_meth_free;
24492f3ab15Sopenharmony_ci
24592f3ab15Sopenharmony_ci    /// Method used to look up certificates and CRLs.
24692f3ab15Sopenharmony_ci    pub struct X509LookupMethod<T>;
24792f3ab15Sopenharmony_ci    /// A reference to an [`X509LookupMethod`].
24892f3ab15Sopenharmony_ci    pub struct X509LookupMethodRef<T>;
24992f3ab15Sopenharmony_ci}
25092f3ab15Sopenharmony_ci
25192f3ab15Sopenharmony_ciforeign_type_and_impl_send_sync! {
25292f3ab15Sopenharmony_ci    type CType = ffi::X509_STORE;
25392f3ab15Sopenharmony_ci    fn drop = ffi::X509_STORE_free;
25492f3ab15Sopenharmony_ci
25592f3ab15Sopenharmony_ci    /// A certificate store to hold trusted `X509` certificates.
25692f3ab15Sopenharmony_ci    pub struct X509Store;
25792f3ab15Sopenharmony_ci    /// Reference to an `X509Store`.
25892f3ab15Sopenharmony_ci    pub struct X509StoreRef;
25992f3ab15Sopenharmony_ci}
26092f3ab15Sopenharmony_ci
26192f3ab15Sopenharmony_ciimpl X509StoreRef {
26292f3ab15Sopenharmony_ci    /// Get a reference to the cache of certificates in this store.
26392f3ab15Sopenharmony_ci    ///
26492f3ab15Sopenharmony_ci    /// This method is deprecated. It is **unsound** and will be removed in a
26592f3ab15Sopenharmony_ci    /// future version of rust-openssl. `X509StoreRef::all_certificates`
26692f3ab15Sopenharmony_ci    /// should be used instead.
26792f3ab15Sopenharmony_ci    #[deprecated(
26892f3ab15Sopenharmony_ci    note = "This method is unsound, and will be removed in a future version of rust-openssl. X509StoreRef::all_certificates should be used instead."
26992f3ab15Sopenharmony_ci    )]
27092f3ab15Sopenharmony_ci    #[corresponds(X509_STORE_get0_objects)]
27192f3ab15Sopenharmony_ci    pub fn objects(&self) -> &StackRef<X509Object> {
27292f3ab15Sopenharmony_ci        unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) }
27392f3ab15Sopenharmony_ci    }
27492f3ab15Sopenharmony_ci
27592f3ab15Sopenharmony_ci    /// Returns a stack of all the certificates in this store.
27692f3ab15Sopenharmony_ci    #[corresponds(X509_STORE_get1_all_certs)]
27792f3ab15Sopenharmony_ci    #[cfg(ossl300)]
27892f3ab15Sopenharmony_ci    pub fn all_certificates(&self) -> Stack<X509> {
27992f3ab15Sopenharmony_ci        unsafe { Stack::from_ptr(ffi::X509_STORE_get1_all_certs(self.as_ptr())) }
28092f3ab15Sopenharmony_ci    }
28192f3ab15Sopenharmony_ci}
28292f3ab15Sopenharmony_ci
28392f3ab15Sopenharmony_cicfg_if! {
28492f3ab15Sopenharmony_ci    if #[cfg(any(boringssl, ossl110, libressl270))] {
28592f3ab15Sopenharmony_ci        use ffi::X509_STORE_get0_objects;
28692f3ab15Sopenharmony_ci    } else {
28792f3ab15Sopenharmony_ci        #[allow(bad_style)]
28892f3ab15Sopenharmony_ci        unsafe fn X509_STORE_get0_objects(x: *mut ffi::X509_STORE) -> *mut ffi::stack_st_X509_OBJECT {
28992f3ab15Sopenharmony_ci            (*x).objs
29092f3ab15Sopenharmony_ci        }
29192f3ab15Sopenharmony_ci    }
29292f3ab15Sopenharmony_ci}
29392f3ab15Sopenharmony_ci
29492f3ab15Sopenharmony_cicfg_if! {
29592f3ab15Sopenharmony_ci    if #[cfg(ossl110)] {
29692f3ab15Sopenharmony_ci        use ffi::X509_LOOKUP_meth_free;
29792f3ab15Sopenharmony_ci    } else {
29892f3ab15Sopenharmony_ci        #[allow(bad_style)]
29992f3ab15Sopenharmony_ci        unsafe fn X509_LOOKUP_meth_free(_x: *mut ffi::X509_LOOKUP_METHOD) {}
30092f3ab15Sopenharmony_ci    }
30192f3ab15Sopenharmony_ci}
302