Skip to main content

rustls_ffi/
certificate.rs

1use std::ffi::CStr;
2use std::marker::PhantomData;
3use std::ptr::null;
4use std::slice;
5
6use libc::{c_char, size_t};
7use rustls::RootCertStore;
8use rustls::pki_types::pem::PemObject;
9use rustls::pki_types::{CertificateDer, PrivateKeyDer};
10use rustls::sign::CertifiedKey;
11
12use crate::crypto_provider::{self, rustls_signing_key};
13use crate::error::{map_error, rustls_result};
14use crate::ffi::{
15    Castable, OwnershipArc, OwnershipBox, OwnershipRef, free_arc, free_box, set_arc_mut_ptr,
16    to_arc_const_ptr, to_boxed_mut_ptr, try_box_from_ptr, try_mut_from_ptr, try_ref_from_ptr,
17    try_ref_from_ptr_ptr, try_slice, try_take,
18};
19use crate::panic::ffi_panic_boundary;
20use crate::rslice::rustls_slice_bytes;
21
22/// An X.509 certificate, as used in rustls.
23/// Corresponds to `CertificateDer` in the Rust pki-types API.
24/// <https://docs.rs/rustls-pki-types/latest/rustls_pki_types/struct.CertificateDer.html>
25pub struct rustls_certificate<'a> {
26    _private: [u8; 0],
27    _marker: PhantomData<&'a ()>,
28}
29
30impl<'a> Castable for rustls_certificate<'a> {
31    type Ownership = OwnershipRef;
32    type RustType = CertificateDer<'a>;
33}
34
35/// Get the DER data of the certificate itself.
36/// The data is owned by the certificate and has the same lifetime.
37#[no_mangle]
38pub extern "C" fn rustls_certificate_get_der(
39    cert: *const rustls_certificate,
40    out_der_data: *mut *const u8,
41    out_der_len: *mut size_t,
42) -> rustls_result {
43    ffi_panic_boundary! {
44        let cert = try_ref_from_ptr!(cert);
45        if out_der_data.is_null() || out_der_len.is_null() {
46            return rustls_result::NullParameter;
47        }
48        let der = cert.as_ref();
49        unsafe {
50            *out_der_data = der.as_ptr();
51            *out_der_len = der.len();
52        }
53        rustls_result::Ok
54    }
55}
56
57/// The complete chain of certificates to send during a TLS handshake,
58/// plus a private key that matches the end-entity (leaf) certificate.
59///
60/// Corresponds to `CertifiedKey` in the Rust API.
61/// <https://docs.rs/rustls/latest/rustls/sign/struct.CertifiedKey.html>
62pub struct rustls_certified_key {
63    _private: [u8; 0],
64}
65
66impl Castable for rustls_certified_key {
67    type Ownership = OwnershipArc;
68    type RustType = CertifiedKey;
69}
70
71impl rustls_certified_key {
72    /// Build a `rustls_certified_key` from a certificate chain and a private key
73    /// and the default process-wide crypto provider.
74    ///
75    /// `cert_chain` must point to a buffer of `cert_chain_len` bytes, containing
76    /// a series of PEM-encoded certificates, with the end-entity (leaf)
77    /// certificate first.
78    ///
79    /// `private_key` must point to a buffer of `private_key_len` bytes, containing
80    /// a PEM-encoded private key in either PKCS#1, PKCS#8 or SEC#1 format when
81    /// using `aws-lc-rs` as the crypto provider. Supported formats may vary by
82    /// provider.
83    ///
84    /// On success, this writes a pointer to the newly created
85    /// `rustls_certified_key` in `certified_key_out`. That pointer must later
86    /// be freed with `rustls_certified_key_free` to avoid memory leaks. Note that
87    /// internally, this is an atomically reference-counted pointer, so even after
88    /// the original caller has called `rustls_certified_key_free`, other objects
89    /// may retain a pointer to the object. The memory will be freed when all
90    /// references are gone.
91    ///
92    /// This function does not take ownership of any of its input pointers. It
93    /// parses the pointed-to data and makes a copy of the result. You may
94    /// free the cert_chain and private_key pointers after calling it.
95    ///
96    /// Typically, you will build a `rustls_certified_key`, use it to create a
97    /// `rustls_server_config` (which increments the reference count), and then
98    /// immediately call `rustls_certified_key_free`. That leaves the
99    /// `rustls_server_config` in possession of the sole reference, so the
100    /// `rustls_certified_key`'s memory will automatically be released when
101    /// the `rustls_server_config` is freed.
102    #[no_mangle]
103    pub extern "C" fn rustls_certified_key_build(
104        cert_chain: *const u8,
105        cert_chain_len: size_t,
106        private_key: *const u8,
107        private_key_len: size_t,
108        certified_key_out: *mut *const rustls_certified_key,
109    ) -> rustls_result {
110        ffi_panic_boundary! {
111            let default_provider =
112                match crypto_provider::get_default_or_install_from_crate_features() {
113                    Some(default_provider) => default_provider,
114                    None => return rustls_result::NoDefaultCryptoProvider,
115                };
116
117            let private_key_der =
118                match PrivateKeyDer::from_pem_slice(try_slice!(private_key, private_key_len)) {
119                    Ok(der) => der,
120                    Err(_) => return rustls_result::PrivateKeyParseError,
121                };
122
123            let private_key = match default_provider
124                .key_provider
125                .load_private_key(private_key_der)
126            {
127                Ok(key) => key,
128                Err(e) => return map_error(e),
129            };
130
131            Self::rustls_certified_key_build_with_signing_key(
132                cert_chain,
133                cert_chain_len,
134                to_boxed_mut_ptr(private_key),
135                certified_key_out,
136            )
137        }
138    }
139
140    /// Build a `rustls_certified_key` from a certificate chain and a
141    /// `rustls_signing_key`.
142    ///
143    /// `cert_chain` must point to a buffer of `cert_chain_len` bytes, containing
144    /// a series of PEM-encoded certificates, with the end-entity (leaf)
145    /// certificate first.
146    ///
147    /// `signing_key` must point to a `rustls_signing_key` loaded using a
148    /// `rustls_crypto_provider` and `rustls_crypto_provider_load_key()`.
149    ///
150    /// On success, this writes a pointer to the newly created
151    /// `rustls_certified_key` in `certified_key_out`. That pointer must later
152    /// be freed with `rustls_certified_key_free` to avoid memory leaks. Note that
153    /// internally, this is an atomically reference-counted pointer, so even after
154    /// the original caller has called `rustls_certified_key_free`, other objects
155    /// may retain a pointer to the object. The memory will be freed when all
156    /// references are gone.
157    ///
158    /// This function does not take ownership of any of its input pointers. It
159    /// parses the pointed-to data and makes a copy of the result. You may
160    /// free the cert_chain and private_key pointers after calling it.
161    ///
162    /// Typically, you will build a `rustls_certified_key`, use it to create a
163    /// `rustls_server_config` (which increments the reference count), and then
164    /// immediately call `rustls_certified_key_free`. That leaves the
165    /// `rustls_server_config` in possession of the sole reference, so the
166    /// `rustls_certified_key`'s memory will automatically be released when
167    /// the `rustls_server_config` is freed.
168    #[no_mangle]
169    pub extern "C" fn rustls_certified_key_build_with_signing_key(
170        cert_chain: *const u8,
171        cert_chain_len: size_t,
172        signing_key: *mut rustls_signing_key,
173        certified_key_out: *mut *const rustls_certified_key,
174    ) -> rustls_result {
175        ffi_panic_boundary! {
176            let cert_chain = try_slice!(cert_chain, cert_chain_len);
177            let signing_key = try_box_from_ptr!(signing_key);
178            let certified_key_out = try_ref_from_ptr_ptr!(certified_key_out);
179
180            let parsed_chain =
181                match CertificateDer::pem_slice_iter(cert_chain).collect::<Result<Vec<_>, _>>() {
182                    Ok(parsed_chain) => parsed_chain,
183                    Err(_) => return rustls_result::CertificateParseError,
184                };
185
186            set_arc_mut_ptr(
187                certified_key_out,
188                CertifiedKey::new(parsed_chain, *signing_key),
189            );
190            rustls_result::Ok
191        }
192    }
193
194    /// Return the i-th rustls_certificate in the rustls_certified_key.
195    ///
196    /// 0 gives the end-entity certificate. 1 and higher give certificates from the chain.
197    ///
198    /// Indexes higher than the last available certificate return NULL.
199    ///
200    /// The returned certificate is valid until the rustls_certified_key is freed.
201    #[no_mangle]
202    pub extern "C" fn rustls_certified_key_get_certificate<'a>(
203        certified_key: *const rustls_certified_key,
204        i: size_t,
205    ) -> *const rustls_certificate<'a> {
206        ffi_panic_boundary! {
207            let certified_key = try_ref_from_ptr!(certified_key);
208            match certified_key.cert.get(i) {
209                Some(cert) => cert as *const CertificateDer as *const _,
210                None => null(),
211            }
212        }
213    }
214
215    /// Create a copy of the rustls_certified_key with the given OCSP response data
216    /// as DER encoded bytes.
217    ///
218    /// The OCSP response may be given as NULL to clear any possibly present OCSP
219    /// data from the cloned key.
220    ///
221    /// The cloned key is independent from its original and needs to be freed
222    /// by the application.
223    #[no_mangle]
224    pub extern "C" fn rustls_certified_key_clone_with_ocsp(
225        certified_key: *const rustls_certified_key,
226        ocsp_response: *const rustls_slice_bytes,
227        cloned_key_out: *mut *const rustls_certified_key,
228    ) -> rustls_result {
229        ffi_panic_boundary! {
230            let cloned_key_out = unsafe {
231                match cloned_key_out.as_mut() {
232                    Some(c) => c,
233                    None => return rustls_result::NullParameter,
234                }
235            };
236            let certified_key = try_ref_from_ptr!(certified_key);
237            let mut new_key = certified_key.clone();
238            if !ocsp_response.is_null() {
239                let ocsp_slice = unsafe { &*ocsp_response };
240                new_key.ocsp = Some(Vec::from(try_slice!(ocsp_slice.data, ocsp_slice.len)));
241            } else {
242                new_key.ocsp = None;
243            }
244            *cloned_key_out = to_arc_const_ptr(new_key);
245            rustls_result::Ok
246        }
247    }
248
249    /// Verify the consistency of this `rustls_certified_key`'s public and private keys.
250    ///
251    /// This is done by performing a comparison of subject public key information (SPKI) bytes
252    /// between the certificate and private key.
253    ///
254    /// If the private key matches the certificate this function returns `RUSTLS_RESULT_OK`,
255    /// otherwise an error `rustls_result` is returned.
256    #[no_mangle]
257    pub extern "C" fn rustls_certified_key_keys_match(
258        key: *const rustls_certified_key,
259    ) -> rustls_result {
260        ffi_panic_boundary! {
261            match try_ref_from_ptr!(key).keys_match() {
262                Ok(_) => rustls_result::Ok,
263                Err(e) => map_error(e),
264            }
265        }
266    }
267
268    /// "Free" a certified_key previously returned from `rustls_certified_key_build`.
269    ///
270    /// Since certified_key is actually an atomically reference-counted pointer,
271    /// extant certified_key may still hold an internal reference to the Rust object.
272    ///
273    /// However, C code must consider this pointer unusable after "free"ing it.
274    ///
275    /// Calling with NULL is fine. Must not be called twice with the same value.
276    #[no_mangle]
277    pub extern "C" fn rustls_certified_key_free(key: *const rustls_certified_key) {
278        ffi_panic_boundary! {
279            free_arc(key);
280        }
281    }
282}
283
284/// A `rustls_root_cert_store` being constructed.
285///
286/// A builder can be modified by adding trust anchor root certificates with
287/// `rustls_root_cert_store_builder_add_pem`. Once you're done adding root certificates,
288/// call `rustls_root_cert_store_builder_build` to turn it into a `rustls_root_cert_store`.
289/// This object is not safe for concurrent mutation.
290pub struct rustls_root_cert_store_builder {
291    _private: [u8; 0],
292}
293
294impl Castable for rustls_root_cert_store_builder {
295    type Ownership = OwnershipBox;
296    type RustType = Option<RootCertStoreBuilder>;
297}
298
299pub(crate) struct RootCertStoreBuilder {
300    roots: RootCertStore,
301}
302
303impl rustls_root_cert_store_builder {
304    /// Create a `rustls_root_cert_store_builder`.
305    ///
306    /// Caller owns the memory and may free it with `rustls_root_cert_store_free`, regardless of
307    /// whether `rustls_root_cert_store_builder_build` was called.
308    ///
309    /// If you wish to abandon the builder without calling `rustls_root_cert_store_builder_build`,
310    /// it must be freed with `rustls_root_cert_store_builder_free`.
311    #[no_mangle]
312    pub extern "C" fn rustls_root_cert_store_builder_new() -> *mut rustls_root_cert_store_builder {
313        ffi_panic_boundary! {
314            let store = RootCertStore::empty();
315            to_boxed_mut_ptr(Some(RootCertStoreBuilder { roots: store }))
316        }
317    }
318
319    /// Add one or more certificates to the root cert store builder using PEM
320    /// encoded data.
321    ///
322    /// When `strict` is true an error will return a `CertificateParseError`
323    /// result. So will an attempt to parse data that has zero certificates.
324    ///
325    /// When `strict` is false, unparseable root certificates will be ignored.
326    /// This may be useful on systems that have syntactically invalid root
327    /// certificates.
328    #[no_mangle]
329    pub extern "C" fn rustls_root_cert_store_builder_add_pem(
330        builder: *mut rustls_root_cert_store_builder,
331        pem: *const u8,
332        pem_len: size_t,
333        strict: bool,
334    ) -> rustls_result {
335        ffi_panic_boundary! {
336            let certs_pem = try_slice!(pem, pem_len);
337            let builder = try_mut_from_ptr!(builder);
338            let builder = match builder {
339                None => return rustls_result::AlreadyUsed,
340                Some(b) => b,
341            };
342
343            let certs =
344                match CertificateDer::pem_slice_iter(certs_pem).collect::<Result<Vec<_>, _>>() {
345                    Ok(certs) => certs,
346                    Err(_) => return rustls_result::CertificateParseError,
347                };
348
349            // We first copy into a temporary root store so we can uphold our
350            // API guideline that there are no partial failures or partial
351            // successes.
352            let mut new_store = RootCertStore::empty();
353            let (parsed, rejected) = new_store.add_parsable_certificates(certs);
354            if strict && (rejected > 0 || parsed == 0) {
355                return rustls_result::CertificateParseError;
356            }
357
358            builder.roots.roots.append(&mut new_store.roots);
359
360            rustls_result::Ok
361        }
362    }
363
364    /// Add one or more certificates to the root cert store builder using PEM
365    /// encoded data read from the named file.
366    ///
367    /// When `strict` is true an error will return a `CertificateParseError`
368    /// result. So will an attempt to parse data that has zero certificates.
369    ///
370    /// When `strict` is false, unparseable root certificates will be ignored.
371    /// This may be useful on systems that have syntactically invalid root
372    /// certificates.
373    #[no_mangle]
374    pub extern "C" fn rustls_root_cert_store_builder_load_roots_from_file(
375        builder: *mut rustls_root_cert_store_builder,
376        filename: *const c_char,
377        strict: bool,
378    ) -> rustls_result {
379        ffi_panic_boundary! {
380            let builder = try_mut_from_ptr!(builder);
381            let builder = match builder {
382                None => return rustls_result::AlreadyUsed,
383                Some(b) => b,
384            };
385
386            let filename = unsafe {
387                if filename.is_null() {
388                    return rustls_result::NullParameter;
389                }
390                CStr::from_ptr(filename)
391            };
392
393            let filename = filename.to_bytes();
394            let filename = match std::str::from_utf8(filename) {
395                Ok(s) => s,
396                Err(_) => return rustls_result::Io,
397            };
398
399            let certs = match CertificateDer::pem_file_iter(filename) {
400                Ok(certs) => certs,
401                Err(_) => return rustls_result::Io,
402            };
403
404            let certs = match certs.collect::<Result<Vec<_>, _>>() {
405                Ok(certs) => certs,
406                Err(_) => return rustls_result::CertificateParseError,
407            };
408
409            // We first copy into a temporary root store so we can uphold our
410            // API guideline that there are no partial failures or partial
411            // successes.
412            let mut roots = RootCertStore::empty();
413            let (parsed, rejected) = roots.add_parsable_certificates(certs);
414            if strict && (rejected > 0 || parsed == 0) {
415                return rustls_result::CertificateParseError;
416            }
417
418            builder.roots.roots.append(&mut roots.roots);
419            rustls_result::Ok
420        }
421    }
422
423    /// Create a new `rustls_root_cert_store` from the builder.
424    ///
425    /// The builder is consumed and cannot be used again, but must still be freed.
426    ///
427    /// The root cert store can be used in several `rustls_web_pki_client_cert_verifier_builder_new`
428    /// instances and must be freed by the application when no longer needed. See the documentation of
429    /// `rustls_root_cert_store_free` for details about lifetime.
430    #[no_mangle]
431    pub extern "C" fn rustls_root_cert_store_builder_build(
432        builder: *mut rustls_root_cert_store_builder,
433        root_cert_store_out: *mut *const rustls_root_cert_store,
434    ) -> rustls_result {
435        ffi_panic_boundary! {
436            let builder = try_mut_from_ptr!(builder);
437            let builder = try_take!(builder);
438            let root_cert_store_out = try_ref_from_ptr_ptr!(root_cert_store_out);
439            set_arc_mut_ptr(root_cert_store_out, builder.roots);
440
441            rustls_result::Ok
442        }
443    }
444
445    /// Free a `rustls_root_cert_store_builder` previously returned from
446    /// `rustls_root_cert_store_builder_new`.
447    ///
448    /// Calling with NULL is fine. Must not be called twice with the same value.
449    #[no_mangle]
450    pub extern "C" fn rustls_root_cert_store_builder_free(
451        builder: *mut rustls_root_cert_store_builder,
452    ) {
453        ffi_panic_boundary! {
454            free_box(builder);
455        }
456    }
457}
458
459/// A root certificate store.
460/// <https://docs.rs/rustls/latest/rustls/struct.RootCertStore.html>
461pub struct rustls_root_cert_store {
462    _private: [u8; 0],
463}
464
465impl Castable for rustls_root_cert_store {
466    type Ownership = OwnershipArc;
467    type RustType = RootCertStore;
468}
469
470impl rustls_root_cert_store {
471    /// Free a rustls_root_cert_store previously returned from rustls_root_cert_store_builder_build.
472    ///
473    /// Calling with NULL is fine. Must not be called twice with the same value.
474    #[no_mangle]
475    pub extern "C" fn rustls_root_cert_store_free(store: *const rustls_root_cert_store) {
476        ffi_panic_boundary! {
477            free_arc(store);
478        }
479    }
480}