Skip to main content

boring/x509/
store.rs

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 boring::x509::store::{X509StoreBuilder, X509Store};
10//! use boring::x509::{X509, X509Name};
11//! use boring::asn1::Asn1Time;
12//! use boring::pkey::PKey;
13//! use boring::hash::MessageDigest;
14//! use boring::rsa::Rsa;
15//! use boring::nid::Nid;
16//!
17//! let rsa = Rsa::generate(2048).unwrap();
18//! let pkey = PKey::from_rsa(rsa).unwrap();
19//! let mut name = X509Name::builder().unwrap();
20//!
21//! name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap();
22//!
23//! let name = name.build();
24//! let mut builder = X509::builder().unwrap();
25//!
26//! // Sep 27th, 2016
27//! let sample_time = Asn1Time::from_unix(1474934400).unwrap();
28//!
29//! builder.set_version(2).unwrap();
30//! builder.set_subject_name(&name).unwrap();
31//! builder.set_issuer_name(&name).unwrap();
32//! builder.set_pubkey(&pkey).unwrap();
33//! builder.set_not_before(&sample_time);
34//! builder.set_not_after(&sample_time);
35//! builder.sign(&pkey, MessageDigest::sha256()).unwrap();
36//!
37//! let certificate: X509 = builder.build();
38//! let mut builder = X509StoreBuilder::new().unwrap();
39//! let _ = builder.add_cert(&certificate);
40//! let store: X509Store = builder.build();
41//! ```
42
43use crate::error::ErrorStack;
44use crate::ffi;
45use crate::stack::StackRef;
46use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef};
47use crate::x509::{X509Object, X509Ref};
48use crate::{cvt, cvt_p};
49use foreign_types::{ForeignType, ForeignTypeRef};
50use openssl_macros::corresponds;
51use std::mem::ManuallyDrop;
52
53foreign_type_and_impl_send_sync! {
54    type CType = ffi::X509_STORE;
55    fn drop = ffi::X509_STORE_free;
56
57    /// A builder type used to construct an `X509Store`.
58    pub struct X509StoreBuilder;
59}
60
61impl X509StoreBuilder {
62    /// Returns a builder for a certificate store.
63    ///
64    /// The store is initially empty.
65    pub fn new() -> Result<X509StoreBuilder, ErrorStack> {
66        unsafe {
67            ffi::init();
68
69            cvt_p(ffi::X509_STORE_new()).map(|p| X509StoreBuilder::from_ptr(p))
70        }
71    }
72
73    /// Constructs the `X509Store`.
74    #[must_use]
75    pub fn build(self) -> X509Store {
76        X509Store(ManuallyDrop::new(self).0)
77    }
78}
79
80impl X509StoreBuilderRef {
81    /// Adds a certificate to the certificate store.
82    #[corresponds(X509_STORE_add_cert)]
83    pub fn add_cert(&mut self, cert: impl AsRef<X509Ref>) -> Result<(), ErrorStack> {
84        let cert = cert.as_ref();
85        unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())) }
86    }
87
88    /// Load certificates from their default locations.
89    ///
90    /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
91    /// environment variables if present, or defaults specified at OpenSSL
92    /// build time otherwise.
93    #[corresponds(X509_STORE_set_default_paths)]
94    pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> {
95        unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())) }
96    }
97
98    /// Sets certificate chain validation related flags.
99    #[corresponds(X509_STORE_set_flags)]
100    pub fn try_set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
101        unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())) }
102    }
103
104    /// Sets certificate chain validation related flags.
105    #[corresponds(X509_STORE_set_flags)]
106    pub fn set_flags(&mut self, flags: X509VerifyFlags) {
107        self.try_set_flags(flags).expect("use try_set_flags");
108    }
109
110    /// Returns a mutable reference to the X509 verification configuration.
111    #[corresponds(X509_STORE_get0_param)]
112    pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
113        unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_get0_param(self.as_ptr())) }
114    }
115
116    /// Sets certificate chain validation related parameters.
117    #[corresponds(X509_STORE_set1_param)]
118    pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> {
119        unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())) }
120    }
121
122    /// For testing only
123    #[cfg(test)]
124    pub fn objects_len(&self) -> usize {
125        unsafe {
126            StackRef::<X509Object>::from_ptr(ffi::X509_STORE_get0_objects(self.as_ptr())).len()
127        }
128    }
129}
130
131foreign_type_and_impl_send_sync! {
132    type CType = ffi::X509_STORE;
133    fn drop = ffi::X509_STORE_free;
134
135    /// A certificate store to hold trusted `X509` certificates.
136    pub struct X509Store;
137}
138
139impl ToOwned for X509StoreRef {
140    type Owned = X509Store;
141
142    fn to_owned(&self) -> X509Store {
143        unsafe {
144            ffi::X509_STORE_up_ref(self.as_ptr());
145            X509Store::from_ptr(self.as_ptr())
146        }
147    }
148}
149
150impl Clone for X509Store {
151    fn clone(&self) -> X509Store {
152        (**self).to_owned()
153    }
154}
155
156impl X509StoreRef {
157    /// **Warning: this method is unsound**
158    ///
159    /// Get a reference to the cache of certificates in this store.
160    ///
161    /// # Safety
162    /// References may be invalidated by any access to the shared cache.
163    #[deprecated(
164        note = "This method is unsound https://github.com/sfackler/rust-openssl/issues/2096"
165    )]
166    #[corresponds(X509_STORE_get0_objects)]
167    #[must_use]
168    pub fn objects(&self) -> &StackRef<X509Object> {
169        unsafe { StackRef::from_ptr(ffi::X509_STORE_get0_objects(self.as_ptr())) }
170    }
171
172    /// For testing only, where it doesn't have to expose an unsafe pointer
173    #[cfg(test)]
174    #[allow(deprecated)]
175    #[must_use]
176    pub fn objects_len(&self) -> usize {
177        self.objects().len()
178    }
179}
180
181#[test]
182#[allow(clippy::redundant_clone)]
183#[should_panic = "Shared X509Store can't be mutated"]
184fn set_cert_store_pevents_mutability() {
185    use crate::ssl::*;
186
187    let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
188    let store = X509StoreBuilder::new().unwrap().build();
189
190    ctx.set_cert_store(store.clone());
191
192    // This is bad.
193    let _aliased_store = ctx.cert_store_mut();
194}