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