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