1 //! Describe a context in which to verify an `X509` certificate.
2 //!
3 //! The `X509` certificate store holds trusted CA certificates used to verify
4 //! peer certificates.
5 //!
6 //! # Example
7 //!
8 //! ```rust
9 //!
10 //! extern crate openssl;
11 //!
12 //! use openssl::x509::store::{X509StoreBuilder, X509Store};
13 //! use openssl::x509::{X509, X509Name};
14 //! use openssl::pkey::PKey;
15 //! use openssl::hash::MessageDigest;
16 //! use openssl::rsa::Rsa;
17 //! use openssl::nid::Nid;
18 //!
19 //! fn main() {
20 //!     let rsa = Rsa::generate(2048).unwrap();
21 //!     let pkey = PKey::from_rsa(rsa).unwrap();
22 //!
23 //!     let mut name = X509Name::builder().unwrap();
24 //!     name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap();
25 //!     let name = name.build();
26 //!
27 //!     let mut builder = X509::builder().unwrap();
28 //!     builder.set_version(2).unwrap();
29 //!     builder.set_subject_name(&name).unwrap();
30 //!     builder.set_issuer_name(&name).unwrap();
31 //!     builder.set_pubkey(&pkey).unwrap();
32 //!     builder.sign(&pkey, MessageDigest::sha256()).unwrap();
33 //!
34 //!     let certificate: X509 = builder.build();
35 //!
36 //!     let mut builder = X509StoreBuilder::new().unwrap();
37 //!     let _ = builder.add_cert(certificate);
38 //!
39 //!     let store: X509Store = builder.build();
40 //! }
41 //! ```
42 
43 use ffi;
44 use foreign_types::ForeignTypeRef;
45 use std::mem;
46 
47 use error::ErrorStack;
48 use stack::StackRef;
49 use x509::{X509Object, X509};
50 use {cvt, cvt_p};
51 
52 foreign_type_and_impl_send_sync! {
53     type CType = ffi::X509_STORE;
54     fn drop = ffi::X509_STORE_free;
55 
56     /// A builder type used to construct an `X509Store`.
57     pub struct X509StoreBuilder;
58     /// Reference to an `X509StoreBuilder`.
59     pub struct X509StoreBuilderRef;
60 }
61 
62 impl X509StoreBuilder {
63     /// Returns a builder for a certificate store.
64     ///
65     /// The store is initially empty.
new() -> Result<X509StoreBuilder, ErrorStack>66     pub fn new() -> Result<X509StoreBuilder, ErrorStack> {
67         unsafe {
68             ffi::init();
69 
70             cvt_p(ffi::X509_STORE_new()).map(X509StoreBuilder)
71         }
72     }
73 
74     /// Constructs the `X509Store`.
build(self) -> X509Store75     pub fn build(self) -> X509Store {
76         let store = X509Store(self.0);
77         mem::forget(self);
78         store
79     }
80 }
81 
82 impl X509StoreBuilderRef {
83     /// Adds a certificate to the certificate store.
84     // FIXME should take an &X509Ref
add_cert(&mut self, cert: X509) -> Result<(), ErrorStack>85     pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
86         unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
87     }
88 
89     /// Load certificates from their default locations.
90     ///
91     /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
92     /// environment variables if present, or defaults specified at OpenSSL
93     /// build time otherwise.
set_default_paths(&mut self) -> Result<(), ErrorStack>94     pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> {
95         unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) }
96     }
97 
98     /// Adds a lookup method to the store.
99     ///
100     /// This corresponds to [`X509_STORE_add_lookup`].
101     ///
102     /// [`X509_STORE_add_lookup`]: https://www.openssl.org/docs/man1.1.1/man3/X509_STORE_add_lookup.html
add_lookup<T>( &mut self, method: &'static X509LookupMethodRef<T>, ) -> Result<&mut X509LookupRef<T>, ErrorStack>103     pub fn add_lookup<T>(
104         &mut self,
105         method: &'static X509LookupMethodRef<T>,
106     ) -> Result<&mut X509LookupRef<T>, ErrorStack> {
107         let lookup = unsafe { ffi::X509_STORE_add_lookup(self.as_ptr(), method.as_ptr()) };
108         cvt_p(lookup).map(|ptr| unsafe { X509LookupRef::from_ptr_mut(ptr) })
109     }
110 }
111 
112 generic_foreign_type_and_impl_send_sync! {
113     type CType = ffi::X509_LOOKUP;
114     fn drop = ffi::X509_LOOKUP_free;
115 
116     /// Information used by an `X509Store` to look up certificates and CRLs.
117     pub struct X509Lookup<T>;
118     /// Reference to an `X509Lookup`.
119     pub struct X509LookupRef<T>;
120 }
121 
122 /// Marker type corresponding to the [`X509_LOOKUP_hash_dir`] lookup method.
123 ///
124 /// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_LOOKUP_hash_dir.html
125 pub struct HashDir;
126 
127 impl X509Lookup<HashDir> {
128     /// Lookup method that loads certificates and CRLs on demand and caches
129     /// them in memory once they are loaded. It also checks for newer CRLs upon
130     /// each lookup, so that newer CRLs are used as soon as they appear in the
131     /// directory.
132     ///
133     /// This corresponds to [`X509_LOOKUP_hash_dir`].
134     ///
135     /// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_LOOKUP_hash_dir.html
hash_dir() -> &'static X509LookupMethodRef<HashDir>136     pub fn hash_dir() -> &'static X509LookupMethodRef<HashDir> {
137         unsafe { X509LookupMethodRef::from_ptr(ffi::X509_LOOKUP_hash_dir()) }
138     }
139 }
140 
141 impl X509LookupRef<HashDir> {
142     /// Specifies a directory from which certificates and CRLs will be loaded
143     /// on-demand. Must be used with `X509Lookup::hash_dir`.
144     ///
145     /// This corresponds to [`X509_LOOKUP_add_dir`].
146     ///
147     /// [`X509_LOOKUP_add_dir`]: https://www.openssl.org/docs/man1.1.1/man3/X509_LOOKUP_add_dir.html
add_dir( &mut self, name: &str, file_type: crate::ssl::SslFiletype, ) -> Result<(), ErrorStack>148     pub fn add_dir(
149         &mut self,
150         name: &str,
151         file_type: crate::ssl::SslFiletype,
152     ) -> Result<(), ErrorStack> {
153         let name = std::ffi::CString::new(name).unwrap();
154         unsafe {
155             cvt(ffi::X509_LOOKUP_add_dir(
156                 self.as_ptr(),
157                 name.as_ptr(),
158                 file_type.as_raw(),
159             ))
160             .map(|_| ())
161         }
162     }
163 }
164 
165 generic_foreign_type_and_impl_send_sync! {
166     type CType = ffi::X509_LOOKUP_METHOD;
167     fn drop = |_method| {
168         #[cfg(ossl110)]
169         ffi::X509_LOOKUP_meth_free(_method);
170     };
171 
172     /// Method used to look up certificates and CRLs.
173     pub struct X509LookupMethod<T>;
174     /// Reference to an `X509LookupMethod`.
175     pub struct X509LookupMethodRef<T>;
176 }
177 
178 foreign_type_and_impl_send_sync! {
179     type CType = ffi::X509_STORE;
180     fn drop = ffi::X509_STORE_free;
181 
182     /// A certificate store to hold trusted `X509` certificates.
183     pub struct X509Store;
184     /// Reference to an `X509Store`.
185     pub struct X509StoreRef;
186 }
187 
188 impl X509StoreRef {
189     /// Get a reference to the cache of certificates in this store.
objects(&self) -> &StackRef<X509Object>190     pub fn objects(&self) -> &StackRef<X509Object> {
191         unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) }
192     }
193 }
194 
195 cfg_if! {
196     if #[cfg(any(ossl110, libressl270))] {
197         use ffi::X509_STORE_get0_objects;
198     } else {
199         #[allow(bad_style)]
200         unsafe fn X509_STORE_get0_objects(x: *mut ffi::X509_STORE) -> *mut ffi::stack_st_X509_OBJECT {
201             (*x).objs
202         }
203     }
204 }
205