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 //! use openssl::x509::store::{X509StoreBuilder, X509Store};
10 //! use openssl::x509::{X509, X509Name};
11 //! use openssl::asn1::Asn1Time;
12 //! use openssl::pkey::PKey;
13 //! use openssl::hash::MessageDigest;
14 //! use openssl::rsa::Rsa;
15 //! use openssl::nid::Nid;
16 //!
17 //! let rsa = Rsa::generate(2048).unwrap();
18 //! let pkey = PKey::from_rsa(rsa).unwrap();
19 //!
20 //! let mut name = X509Name::builder().unwrap();
21 //! name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap();
22 //! let name = name.build();
23 //!
24 //! // Sep 27th, 2016
25 //! let sample_time = Asn1Time::from_unix(1474934400).unwrap();
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.set_not_before(&sample_time);
33 //! builder.set_not_after(&sample_time);
34 //! builder.sign(&pkey, MessageDigest::sha256()).unwrap();
35 //!
36 //! let certificate: X509 = builder.build();
37 //!
38 //! let mut builder = X509StoreBuilder::new().unwrap();
39 //! let _ = builder.add_cert(certificate);
40 //!
41 //! let store: X509Store = builder.build();
42 //! ```
43 
44 use cfg_if::cfg_if;
45 use foreign_types::{ForeignType, ForeignTypeRef};
46 use std::mem;
47 
48 use crate::error::ErrorStack;
49 #[cfg(not(boringssl))]
50 use crate::ssl::SslFiletype;
51 #[cfg(ossl300)]
52 use crate::stack::Stack;
53 use crate::stack::StackRef;
54 use crate::util::ForeignTypeRefExt;
55 #[cfg(any(ossl102, boringssl, libressl261))]
56 use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef};
57 use crate::x509::{X509Object, X509PurposeId, X509};
58 use crate::{cvt, cvt_p};
59 use openssl_macros::corresponds;
60 #[cfg(not(boringssl))]
61 use std::ffi::CString;
62 #[cfg(not(boringssl))]
63 use std::path::Path;
64 
65 foreign_type_and_impl_send_sync! {
66     type CType = ffi::X509_STORE;
67     fn drop = ffi::X509_STORE_free;
68 
69     /// A builder type used to construct an `X509Store`.
70     pub struct X509StoreBuilder;
71     /// A reference to an [`X509StoreBuilder`].
72     pub struct X509StoreBuilderRef;
73 }
74 
75 impl X509StoreBuilder {
76     /// Returns a builder for a certificate store.
77     ///
78     /// The store is initially empty.
79     #[corresponds(X509_STORE_new)]
new() -> Result<X509StoreBuilder, ErrorStack>80     pub fn new() -> Result<X509StoreBuilder, ErrorStack> {
81         unsafe {
82             ffi::init();
83 
84             cvt_p(ffi::X509_STORE_new()).map(X509StoreBuilder)
85         }
86     }
87 
88     /// Constructs the `X509Store`.
build(self) -> X509Store89     pub fn build(self) -> X509Store {
90         let store = X509Store(self.0);
91         mem::forget(self);
92         store
93     }
94 }
95 
96 impl X509StoreBuilderRef {
97     /// Adds a certificate to the certificate store.
98     // FIXME should take an &X509Ref
99     #[corresponds(X509_STORE_add_cert)]
add_cert(&mut self, cert: X509) -> Result<(), ErrorStack>100     pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
101         unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
102     }
103 
104     /// Load certificates from their default locations.
105     ///
106     /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
107     /// environment variables if present, or defaults specified at OpenSSL
108     /// build time otherwise.
109     #[corresponds(X509_STORE_set_default_paths)]
set_default_paths(&mut self) -> Result<(), ErrorStack>110     pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> {
111         unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) }
112     }
113 
114     /// Adds a lookup method to the store.
115     #[corresponds(X509_STORE_add_lookup)]
add_lookup<T>( &mut self, method: &'static X509LookupMethodRef<T>, ) -> Result<&mut X509LookupRef<T>, ErrorStack>116     pub fn add_lookup<T>(
117         &mut self,
118         method: &'static X509LookupMethodRef<T>,
119     ) -> Result<&mut X509LookupRef<T>, ErrorStack> {
120         let lookup = unsafe { ffi::X509_STORE_add_lookup(self.as_ptr(), method.as_ptr()) };
121         cvt_p(lookup).map(|ptr| unsafe { X509LookupRef::from_ptr_mut(ptr) })
122     }
123 
124     /// Sets certificate chain validation related flags.
125     #[corresponds(X509_STORE_set_flags)]
126     #[cfg(any(ossl102, boringssl, libressl261))]
set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack>127     pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
128         unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) }
129     }
130 
131     /// Sets the certificate purpose.
132     /// The purpose value can be obtained by `X509PurposeRef::get_by_sname()`
133     #[corresponds(X509_STORE_set_purpose)]
set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack>134     pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> {
135         unsafe { cvt(ffi::X509_STORE_set_purpose(self.as_ptr(), purpose.as_raw())).map(|_| ()) }
136     }
137 
138     /// Sets certificate chain validation related parameters.
139     #[corresponds[X509_STORE_set1_param]]
140     #[cfg(any(ossl102, boringssl, libressl261))]
set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack>141     pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> {
142         unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())).map(|_| ()) }
143     }
144 }
145 
146 generic_foreign_type_and_impl_send_sync! {
147     type CType = ffi::X509_LOOKUP;
148     fn drop = ffi::X509_LOOKUP_free;
149 
150     /// Information used by an `X509Store` to look up certificates and CRLs.
151     pub struct X509Lookup<T>;
152     /// A reference to an [`X509Lookup`].
153     pub struct X509LookupRef<T>;
154 }
155 
156 /// Marker type corresponding to the [`X509_LOOKUP_hash_dir`] lookup method.
157 ///
158 /// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/manmaster/crypto/X509_LOOKUP_hash_dir.html
159 // FIXME should be an enum
160 pub struct HashDir;
161 
162 impl X509Lookup<HashDir> {
163     /// Lookup method that loads certificates and CRLs on demand and caches
164     /// them in memory once they are loaded. It also checks for newer CRLs upon
165     /// each lookup, so that newer CRLs are used as soon as they appear in the
166     /// directory.
167     #[corresponds(X509_LOOKUP_hash_dir)]
hash_dir() -> &'static X509LookupMethodRef<HashDir>168     pub fn hash_dir() -> &'static X509LookupMethodRef<HashDir> {
169         unsafe { X509LookupMethodRef::from_const_ptr(ffi::X509_LOOKUP_hash_dir()) }
170     }
171 }
172 
173 #[cfg(not(boringssl))]
174 impl X509LookupRef<HashDir> {
175     /// Specifies a directory from which certificates and CRLs will be loaded
176     /// on-demand. Must be used with `X509Lookup::hash_dir`.
177     #[corresponds(X509_LOOKUP_add_dir)]
add_dir(&mut self, name: &str, file_type: SslFiletype) -> Result<(), ErrorStack>178     pub fn add_dir(&mut self, name: &str, file_type: SslFiletype) -> Result<(), ErrorStack> {
179         let name = CString::new(name).unwrap();
180         unsafe {
181             cvt(ffi::X509_LOOKUP_add_dir(
182                 self.as_ptr(),
183                 name.as_ptr(),
184                 file_type.as_raw(),
185             ))
186             .map(|_| ())
187         }
188     }
189 }
190 
191 /// Marker type corresponding to the [`X509_LOOKUP_file`] lookup method.
192 ///
193 /// [`X509_LOOKUP_file`]: https://www.openssl.org/docs/man1.1.1/man3/X509_LOOKUP_file.html
194 pub struct File;
195 
196 impl X509Lookup<File> {
197     /// Lookup method loads all the certificates or CRLs present in a file
198     /// into memory at the time the file is added as a lookup source.
199     #[corresponds(X509_LOOKUP_file)]
file() -> &'static X509LookupMethodRef<File>200     pub fn file() -> &'static X509LookupMethodRef<File> {
201         unsafe { X509LookupMethodRef::from_const_ptr(ffi::X509_LOOKUP_file()) }
202     }
203 }
204 
205 #[cfg(not(boringssl))]
206 impl X509LookupRef<File> {
207     /// Specifies a file from which certificates will be loaded
208     #[corresponds(X509_load_cert_file)]
209     // FIXME should return 'Result<i32, ErrorStack' like load_crl_file
load_cert_file<P: AsRef<Path>>( &mut self, file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack>210     pub fn load_cert_file<P: AsRef<Path>>(
211         &mut self,
212         file: P,
213         file_type: SslFiletype,
214     ) -> Result<(), ErrorStack> {
215         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
216         unsafe {
217             cvt(ffi::X509_load_cert_file(
218                 self.as_ptr(),
219                 file.as_ptr(),
220                 file_type.as_raw(),
221             ))
222             .map(|_| ())
223         }
224     }
225 
226     /// Specifies a file from which certificate revocation lists will be loaded
227     #[corresponds(X509_load_crl_file)]
load_crl_file<P: AsRef<Path>>( &mut self, file: P, file_type: SslFiletype, ) -> Result<i32, ErrorStack>228     pub fn load_crl_file<P: AsRef<Path>>(
229         &mut self,
230         file: P,
231         file_type: SslFiletype,
232     ) -> Result<i32, ErrorStack> {
233         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
234         unsafe {
235             cvt(ffi::X509_load_crl_file(
236                 self.as_ptr(),
237                 file.as_ptr(),
238                 file_type.as_raw(),
239             ))
240         }
241     }
242 }
243 
244 generic_foreign_type_and_impl_send_sync! {
245     type CType = ffi::X509_LOOKUP_METHOD;
246     fn drop = X509_LOOKUP_meth_free;
247 
248     /// Method used to look up certificates and CRLs.
249     pub struct X509LookupMethod<T>;
250     /// A reference to an [`X509LookupMethod`].
251     pub struct X509LookupMethodRef<T>;
252 }
253 
254 foreign_type_and_impl_send_sync! {
255     type CType = ffi::X509_STORE;
256     fn drop = ffi::X509_STORE_free;
257 
258     /// A certificate store to hold trusted `X509` certificates.
259     pub struct X509Store;
260     /// Reference to an `X509Store`.
261     pub struct X509StoreRef;
262 }
263 
264 impl X509StoreRef {
265     /// Get a reference to the cache of certificates in this store.
266     ///
267     /// This method is deprecated. It is **unsound** and will be removed in a
268     /// future version of rust-openssl. `X509StoreRef::all_certificates`
269     /// should be used instead.
270     #[deprecated(
271         note = "This method is unsound, and will be removed in a future version of rust-openssl. X509StoreRef::all_certificates should be used instead."
272     )]
273     #[corresponds(X509_STORE_get0_objects)]
objects(&self) -> &StackRef<X509Object>274     pub fn objects(&self) -> &StackRef<X509Object> {
275         unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) }
276     }
277 
278     /// Returns a stack of all the certificates in this store.
279     #[corresponds(X509_STORE_get1_all_certs)]
280     #[cfg(ossl300)]
all_certificates(&self) -> Stack<X509>281     pub fn all_certificates(&self) -> Stack<X509> {
282         unsafe { Stack::from_ptr(ffi::X509_STORE_get1_all_certs(self.as_ptr())) }
283     }
284 }
285 
286 cfg_if! {
287     if #[cfg(any(boringssl, ossl110, libressl270))] {
288         use ffi::X509_STORE_get0_objects;
289     } else {
290         #[allow(bad_style)]
291         unsafe fn X509_STORE_get0_objects(x: *mut ffi::X509_STORE) -> *mut ffi::stack_st_X509_OBJECT {
292             (*x).objs
293         }
294     }
295 }
296 
297 cfg_if! {
298     if #[cfg(ossl110)] {
299         use ffi::X509_LOOKUP_meth_free;
300     } else {
301         #[allow(bad_style)]
302         unsafe fn X509_LOOKUP_meth_free(_x: *mut ffi::X509_LOOKUP_METHOD) {}
303     }
304 }
305