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 set_flags(&mut self, flags: X509VerifyFlags) {
101        unsafe {
102            cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).unwrap();
103        }
104    }
105
106    /// Returns a mutable reference to the X509 verification configuration.
107    #[corresponds(X509_STORE_get0_param)]
108    pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
109        unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_get0_param(self.as_ptr())) }
110    }
111
112    /// Sets certificate chain validation related parameters.
113    #[corresponds(X509_STORE_set1_param)]
114    pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> {
115        unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())) }
116    }
117
118    /// For testing only
119    #[cfg(test)]
120    pub fn objects_len(&self) -> usize {
121        unsafe {
122            StackRef::<X509Object>::from_ptr(ffi::X509_STORE_get0_objects(self.as_ptr())).len()
123        }
124    }
125}
126
127foreign_type_and_impl_send_sync! {
128    type CType = ffi::X509_STORE;
129    fn drop = ffi::X509_STORE_free;
130
131    /// A certificate store to hold trusted `X509` certificates.
132    pub struct X509Store;
133}
134
135impl ToOwned for X509StoreRef {
136    type Owned = X509Store;
137
138    fn to_owned(&self) -> X509Store {
139        unsafe {
140            ffi::X509_STORE_up_ref(self.as_ptr());
141            X509Store::from_ptr(self.as_ptr())
142        }
143    }
144}
145
146impl Clone for X509Store {
147    fn clone(&self) -> X509Store {
148        (**self).to_owned()
149    }
150}
151
152impl X509StoreRef {
153    /// **Warning: this method is unsound**
154    ///
155    /// Get a reference to the cache of certificates in this store.
156    ///
157    /// # Safety
158    /// References may be invalidated by any access to the shared cache.
159    #[deprecated(
160        note = "This method is unsound https://github.com/sfackler/rust-openssl/issues/2096"
161    )]
162    #[corresponds(X509_STORE_get0_objects)]
163    #[must_use]
164    pub fn objects(&self) -> &StackRef<X509Object> {
165        unsafe { StackRef::from_ptr(ffi::X509_STORE_get0_objects(self.as_ptr())) }
166    }
167
168    /// For testing only, where it doesn't have to expose an unsafe pointer
169    #[cfg(test)]
170    #[allow(deprecated)]
171    #[must_use]
172    pub fn objects_len(&self) -> usize {
173        self.objects().len()
174    }
175}
176
177#[test]
178#[allow(clippy::redundant_clone)]
179#[should_panic = "Shared X509Store can't be mutated"]
180fn set_cert_store_pevents_mutability() {
181    use crate::ssl::*;
182
183    let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
184    let store = X509StoreBuilder::new().unwrap().build();
185
186    ctx.set_cert_store(store.clone());
187
188    // This is bad.
189    let _aliased_store = ctx.cert_store_mut();
190}