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