Skip to main content

rustls_ffi/
verifier.rs

1use std::slice;
2use std::sync::Arc;
3
4use libc::size_t;
5use rustls::client::WebPkiServerVerifier;
6use rustls::client::danger::ServerCertVerifier;
7use rustls::crypto::CryptoProvider;
8use rustls::pki_types::CertificateRevocationListDer;
9use rustls::pki_types::pem::PemObject;
10use rustls::server::WebPkiClientVerifier;
11use rustls::server::danger::ClientCertVerifier;
12use rustls::{DistinguishedName, RootCertStore};
13use webpki::{ExpirationPolicy, RevocationCheckDepth, UnknownStatusPolicy};
14
15use crate::certificate::rustls_root_cert_store;
16use crate::crypto_provider::{self, rustls_crypto_provider};
17use crate::error::{self, rustls_result};
18use crate::ffi::{
19    Castable, OwnershipBox, free_box, set_boxed_mut_ptr, to_boxed_mut_ptr, try_clone_arc,
20    try_mut_from_ptr, try_mut_from_ptr_ptr, try_slice, try_take,
21};
22use crate::panic::ffi_panic_boundary;
23
24/// A built client certificate verifier that can be provided to a `rustls_server_config_builder`
25/// with `rustls_server_config_builder_set_client_verifier`.
26//
27// Rustls' ConfigBuilder requires an `Arc<dyn ClientCertVerifier>` here, meaning we
28// must follow the pattern described in CONTRIBUTING.md[^0] for handling dynamically sized
29// types (DSTs) across the FFI boundary.
30// [^0]: <https://github.com/rustls/rustls-ffi/blob/main/CONTRIBUTING.md#dynamically-sized-types>
31pub struct rustls_client_cert_verifier {
32    _private: [u8; 0],
33}
34
35impl Castable for rustls_client_cert_verifier {
36    type Ownership = OwnershipBox;
37    type RustType = Arc<dyn ClientCertVerifier>;
38}
39
40impl rustls_client_cert_verifier {
41    /// Free a `rustls_client_cert_verifier` previously returned from
42    /// `rustls_client_cert_verifier_builder_build`. Calling with NULL is fine. Must not be
43    /// called twice with the same value.
44    #[no_mangle]
45    pub extern "C" fn rustls_client_cert_verifier_free(verifier: *mut rustls_client_cert_verifier) {
46        ffi_panic_boundary! {
47            free_box(verifier);
48        }
49    }
50}
51
52pub(crate) struct ClientCertVerifierBuilder {
53    provider: Option<Arc<CryptoProvider>>,
54    roots: Arc<RootCertStore>,
55    root_hint_subjects: Vec<DistinguishedName>,
56    crls: Vec<CertificateRevocationListDer<'static>>,
57    revocation_depth: RevocationCheckDepth,
58    revocation_policy: UnknownStatusPolicy,
59    allow_unauthenticated: bool,
60}
61
62/// A client certificate verifier being constructed.
63///
64/// A builder can be modified by, e.g. `rustls_web_pki_client_cert_verifier_builder_add_crl`.
65///
66/// Once you're done configuring settings, call `rustls_web_pki_client_cert_verifier_builder_build`
67/// to turn it into a `rustls_client_cert_verifier`.
68///
69/// This object is not safe for concurrent mutation.
70///
71/// See <https://docs.rs/rustls/latest/rustls/server/struct.ClientCertVerifierBuilder.html>
72/// for more information.
73pub struct rustls_web_pki_client_cert_verifier_builder {
74    _private: [u8; 0],
75}
76
77impl Castable for rustls_web_pki_client_cert_verifier_builder {
78    type Ownership = OwnershipBox;
79    type RustType = Option<ClientCertVerifierBuilder>;
80}
81
82impl rustls_web_pki_client_cert_verifier_builder {
83    /// Create a `rustls_web_pki_client_cert_verifier_builder` using the process-wide default
84    /// cryptography provider.
85    ///
86    /// Caller owns the memory and may eventually call `rustls_web_pki_client_cert_verifier_builder_free`
87    /// to free it, whether or not `rustls_web_pki_client_cert_verifier_builder_build` was called.
88    ///
89    /// Without further modification the builder will produce a client certificate verifier that
90    /// will require a client present a client certificate that chains to one of the trust anchors
91    /// in the provided `rustls_root_cert_store`. The root cert store must not be empty.
92    ///
93    /// Revocation checking will not be performed unless
94    /// `rustls_web_pki_client_cert_verifier_builder_add_crl` is used to add certificate revocation
95    /// lists (CRLs) to the builder. If CRLs are added, revocation checking will be performed
96    /// for the entire certificate chain unless
97    /// `rustls_web_pki_client_cert_verifier_only_check_end_entity_revocation` is used. Unknown
98    /// revocation status for certificates considered for revocation status will be treated as
99    /// an error unless `rustls_web_pki_client_cert_verifier_allow_unknown_revocation_status` is
100    /// used.
101    ///
102    /// Unauthenticated clients will not be permitted unless
103    /// `rustls_web_pki_client_cert_verifier_builder_allow_unauthenticated` is used.
104    ///
105    /// This copies the contents of the `rustls_root_cert_store`. It does not take
106    /// ownership of the pointed-to data.
107    #[no_mangle]
108    pub extern "C" fn rustls_web_pki_client_cert_verifier_builder_new(
109        store: *const rustls_root_cert_store,
110    ) -> *mut rustls_web_pki_client_cert_verifier_builder {
111        ffi_panic_boundary! {
112            let store = try_clone_arc!(store);
113            to_boxed_mut_ptr(Some(ClientCertVerifierBuilder {
114                provider: crypto_provider::get_default_or_install_from_crate_features(),
115                root_hint_subjects: store.subjects(),
116                roots: store,
117                crls: Vec::default(),
118                revocation_depth: RevocationCheckDepth::Chain,
119                revocation_policy: UnknownStatusPolicy::Deny,
120                allow_unauthenticated: false,
121            }))
122        }
123    }
124
125    /// Create a `rustls_web_pki_client_cert_verifier_builder` using the specified
126    /// cryptography provider.
127    ///
128    /// Caller owns the memory and may eventually call
129    /// `rustls_web_pki_client_cert_verifier_builder_free` to free it, whether or
130    /// not `rustls_web_pki_client_cert_verifier_builder_build` was called.
131    ///
132    /// Without further modification the builder will produce a client certificate verifier that
133    /// will require a client present a client certificate that chains to one of the trust anchors
134    /// in the provided `rustls_root_cert_store`. The root cert store must not be empty.
135    ///
136    /// Revocation checking will not be performed unless
137    /// `rustls_web_pki_client_cert_verifier_builder_add_crl` is used to add certificate revocation
138    /// lists (CRLs) to the builder. If CRLs are added, revocation checking will be performed
139    /// for the entire certificate chain unless
140    /// `rustls_web_pki_client_cert_verifier_only_check_end_entity_revocation` is used. Unknown
141    /// revocation status for certificates considered for revocation status will be treated as
142    /// an error unless `rustls_web_pki_client_cert_verifier_allow_unknown_revocation_status` is
143    /// used.
144    ///
145    /// Unauthenticated clients will not be permitted unless
146    /// `rustls_web_pki_client_cert_verifier_builder_allow_unauthenticated` is used.
147    ///
148    /// This copies the contents of the `rustls_root_cert_store`. It does not take
149    /// ownership of the pointed-to data.
150    #[no_mangle]
151    pub extern "C" fn rustls_web_pki_client_cert_verifier_builder_new_with_provider(
152        provider: *const rustls_crypto_provider,
153        store: *const rustls_root_cert_store,
154    ) -> *mut rustls_web_pki_client_cert_verifier_builder {
155        ffi_panic_boundary! {
156            let provider = try_clone_arc!(provider);
157            let store = try_clone_arc!(store);
158            to_boxed_mut_ptr(Some(ClientCertVerifierBuilder {
159                provider: Some(provider),
160                root_hint_subjects: store.subjects(),
161                roots: store,
162                crls: Vec::default(),
163                revocation_depth: RevocationCheckDepth::Chain,
164                revocation_policy: UnknownStatusPolicy::Deny,
165                allow_unauthenticated: false,
166            }))
167        }
168    }
169
170    /// Add one or more certificate revocation lists (CRLs) to the client certificate verifier
171    /// builder by reading the CRL content from the provided buffer of PEM encoded content.
172    ///
173    /// By default revocation checking will be performed on the entire certificate chain. To only
174    /// check the revocation status of the end entity certificate, use
175    /// `rustls_web_pki_client_cert_verifier_only_check_end_entity_revocation`.
176    ///
177    /// This function returns an error if the provided buffer is not valid PEM encoded content.
178    #[no_mangle]
179    pub extern "C" fn rustls_web_pki_client_cert_verifier_builder_add_crl(
180        builder: *mut rustls_web_pki_client_cert_verifier_builder,
181        crl_pem: *const u8,
182        crl_pem_len: size_t,
183    ) -> rustls_result {
184        ffi_panic_boundary! {
185            let client_verifier_builder = try_mut_from_ptr!(builder);
186            let client_verifier_builder = match client_verifier_builder {
187                None => return rustls_result::AlreadyUsed,
188                Some(v) => v,
189            };
190
191            let crls_der = match CertificateRevocationListDer::pem_slice_iter(try_slice!(
192                crl_pem,
193                crl_pem_len
194            ))
195            .collect::<Result<Vec<_>, _>>()
196            {
197                Ok(crls_der) => crls_der,
198                Err(_) => return rustls_result::CertificateRevocationListParseError,
199            };
200
201            if crls_der.is_empty() {
202                return rustls_result::CertificateRevocationListParseError;
203            }
204
205            client_verifier_builder.crls.extend(crls_der);
206            rustls_result::Ok
207        }
208    }
209
210    /// When CRLs are provided with `rustls_web_pki_client_cert_verifier_builder_add_crl`, only
211    /// check the revocation status of end entity certificates, ignoring any intermediate certificates
212    /// in the chain.
213    #[no_mangle]
214    pub extern "C" fn rustls_web_pki_client_cert_verifier_only_check_end_entity_revocation(
215        builder: *mut rustls_web_pki_client_cert_verifier_builder,
216    ) -> rustls_result {
217        ffi_panic_boundary! {
218            let client_verifier_builder = try_mut_from_ptr!(builder);
219            let client_verifier_builder = match client_verifier_builder {
220                None => return rustls_result::AlreadyUsed,
221                Some(v) => v,
222            };
223
224            client_verifier_builder.revocation_depth = RevocationCheckDepth::EndEntity;
225            rustls_result::Ok
226        }
227    }
228
229    /// When CRLs are provided with `rustls_web_pki_client_cert_verifier_builder_add_crl`, and it
230    /// isn't possible to determine the revocation status of a considered certificate, do not treat
231    /// it as an error condition.
232    ///
233    /// Overrides the default behavior where unknown revocation status is considered an error.
234    #[no_mangle]
235    pub extern "C" fn rustls_web_pki_client_cert_verifier_allow_unknown_revocation_status(
236        builder: *mut rustls_web_pki_client_cert_verifier_builder,
237    ) -> rustls_result {
238        ffi_panic_boundary! {
239            let client_verifier_builder = try_mut_from_ptr!(builder);
240            let client_verifier_builder = match client_verifier_builder {
241                None => return rustls_result::AlreadyUsed,
242                Some(v) => v,
243            };
244
245            client_verifier_builder.revocation_policy = UnknownStatusPolicy::Allow;
246            rustls_result::Ok
247        }
248    }
249
250    /// Allow unauthenticated anonymous clients in addition to those that present a client
251    /// certificate that chains to one of the verifier's configured trust anchors.
252    #[no_mangle]
253    pub extern "C" fn rustls_web_pki_client_cert_verifier_builder_allow_unauthenticated(
254        builder: *mut rustls_web_pki_client_cert_verifier_builder,
255    ) -> rustls_result {
256        ffi_panic_boundary! {
257            let client_verifier_builder = try_mut_from_ptr!(builder);
258            let client_verifier_builder = match client_verifier_builder {
259                None => return rustls_result::AlreadyUsed,
260                Some(v) => v,
261            };
262
263            client_verifier_builder.allow_unauthenticated = true;
264            rustls_result::Ok
265        }
266    }
267
268    /// Clear the list of trust anchor hint subjects.
269    ///
270    /// By default, the client cert verifier will use the subjects provided by the root cert
271    /// store configured for client authentication. Calling this function will remove these
272    /// hint subjects, indicating the client should make a free choice of which certificate
273    /// to send.
274    #[no_mangle]
275    pub extern "C" fn rustls_web_pki_client_cert_verifier_clear_root_hint_subjects(
276        builder: *mut rustls_web_pki_client_cert_verifier_builder,
277    ) -> rustls_result {
278        ffi_panic_boundary! {
279            let client_verifier_builder = try_mut_from_ptr!(builder);
280            let client_verifier_builder = match client_verifier_builder {
281                None => return rustls_result::AlreadyUsed,
282                Some(v) => v,
283            };
284
285            client_verifier_builder.root_hint_subjects.clear();
286            rustls_result::Ok
287        }
288    }
289
290    /// Add additional distinguished names to the list of trust anchor hint subjects.
291    ///
292    /// By default, the client cert verifier will use the subjects provided by the root cert
293    /// store configured for client authentication. Calling this function will add to these
294    /// existing hint subjects. Calling this function with an empty `store` will have no
295    /// effect, use `rustls_web_pki_client_cert_verifier_clear_root_hint_subjects` to clear
296    /// the subject hints.
297    #[no_mangle]
298    pub extern "C" fn rustls_web_pki_client_cert_verifier_add_root_hint_subjects(
299        builder: *mut rustls_web_pki_client_cert_verifier_builder,
300        store: *const rustls_root_cert_store,
301    ) -> rustls_result {
302        let client_verifier_builder = try_mut_from_ptr!(builder);
303        let client_verifier_builder = match client_verifier_builder {
304            None => return rustls_result::AlreadyUsed,
305            Some(v) => v,
306        };
307
308        let store = try_clone_arc!(store);
309        client_verifier_builder.root_hint_subjects = store.subjects();
310        rustls_result::Ok
311    }
312
313    /// Create a new client certificate verifier from the builder.
314    ///
315    /// The builder is consumed and cannot be used again, but must still be freed.
316    ///
317    /// The verifier can be used in several `rustls_server_config` instances and must be
318    /// freed by the application when no longer needed. See the documentation of
319    /// `rustls_web_pki_client_cert_verifier_builder_free` for details about lifetime.
320    #[no_mangle]
321    pub extern "C" fn rustls_web_pki_client_cert_verifier_builder_build(
322        builder: *mut rustls_web_pki_client_cert_verifier_builder,
323        verifier_out: *mut *mut rustls_client_cert_verifier,
324    ) -> rustls_result {
325        ffi_panic_boundary! {
326            let client_verifier_builder = try_mut_from_ptr!(builder);
327            let client_verifier_builder = try_take!(client_verifier_builder);
328            let verifier_out = try_mut_from_ptr_ptr!(verifier_out);
329
330            let builder = match client_verifier_builder.provider {
331                Some(provider) => WebPkiClientVerifier::builder_with_provider(
332                    client_verifier_builder.roots,
333                    provider,
334                ),
335                None => WebPkiClientVerifier::builder(client_verifier_builder.roots),
336            };
337
338            let mut builder = builder.with_crls(client_verifier_builder.crls);
339            match client_verifier_builder.revocation_depth {
340                RevocationCheckDepth::EndEntity => {
341                    builder = builder.only_check_end_entity_revocation()
342                }
343                RevocationCheckDepth::Chain => {}
344            }
345            match client_verifier_builder.revocation_policy {
346                UnknownStatusPolicy::Allow => builder = builder.allow_unknown_revocation_status(),
347                UnknownStatusPolicy::Deny => {}
348            }
349            if client_verifier_builder.allow_unauthenticated {
350                builder = builder.allow_unauthenticated();
351            }
352            if client_verifier_builder.root_hint_subjects.is_empty() {
353                builder = builder.clear_root_hint_subjects();
354            } else {
355                builder =
356                    builder.add_root_hint_subjects(client_verifier_builder.root_hint_subjects);
357            }
358
359            let verifier = match builder.build() {
360                Ok(v) => v,
361                Err(e) => return error::map_verifier_builder_error(e),
362            };
363
364            set_boxed_mut_ptr(verifier_out, verifier);
365            rustls_result::Ok
366        }
367    }
368
369    /// Free a `rustls_client_cert_verifier_builder` previously returned from
370    /// `rustls_client_cert_verifier_builder_new`.
371    ///
372    /// Calling with NULL is fine. Must not be called twice with the same value.
373    #[no_mangle]
374    pub extern "C" fn rustls_web_pki_client_cert_verifier_builder_free(
375        builder: *mut rustls_web_pki_client_cert_verifier_builder,
376    ) {
377        ffi_panic_boundary! {
378            free_box(builder);
379        }
380    }
381}
382
383/// A server certificate verifier being constructed.
384///
385/// A builder can be modified by, e.g. `rustls_web_pki_server_cert_verifier_builder_add_crl`.
386///
387/// Once you're done configuring settings, call `rustls_web_pki_server_cert_verifier_builder_build`
388/// to turn it into a `rustls_server_cert_verifier`. This object is not safe for concurrent mutation.
389///
390/// See <https://docs.rs/rustls/latest/rustls/client/struct.ServerCertVerifierBuilder.html>
391/// for more information.
392pub struct rustls_web_pki_server_cert_verifier_builder {
393    _private: [u8; 0],
394}
395
396impl Castable for rustls_web_pki_server_cert_verifier_builder {
397    type Ownership = OwnershipBox;
398    type RustType = Option<ServerCertVerifierBuilder>;
399}
400
401pub(crate) struct ServerCertVerifierBuilder {
402    provider: Option<Arc<CryptoProvider>>,
403    roots: Arc<RootCertStore>,
404    crls: Vec<CertificateRevocationListDer<'static>>,
405    revocation_depth: RevocationCheckDepth,
406    revocation_policy: UnknownStatusPolicy,
407    revocation_expiration_policy: ExpirationPolicy,
408}
409
410impl ServerCertVerifierBuilder {
411    /// Create a `rustls_web_pki_server_cert_verifier_builder` using the process-wide default
412    /// crypto provider.
413    ///
414    /// Caller owns the memory and may free it with `rustls_web_pki_server_cert_verifier_builder_free`,
415    /// regardless of whether `rustls_web_pki_server_cert_verifier_builder_build` was called.
416    ///
417    /// Without further modification the builder will produce a server certificate verifier that
418    /// will require a server present a certificate that chains to one of the trust anchors
419    /// in the provided `rustls_root_cert_store`. The root cert store must not be empty.
420    ///
421    /// Revocation checking will not be performed unless
422    /// `rustls_web_pki_server_cert_verifier_builder_add_crl` is used to add certificate revocation
423    /// lists (CRLs) to the builder.  If CRLs are added, revocation checking will be performed
424    /// for the entire certificate chain unless
425    /// `rustls_web_pki_server_cert_verifier_only_check_end_entity_revocation` is used. Unknown
426    /// revocation status for certificates considered for revocation status will be treated as
427    /// an error unless `rustls_web_pki_server_cert_verifier_allow_unknown_revocation_status` is
428    /// used.
429    ///
430    /// This copies the contents of the `rustls_root_cert_store`. It does not take
431    /// ownership of the pointed-to data.
432    #[no_mangle]
433    pub extern "C" fn rustls_web_pki_server_cert_verifier_builder_new(
434        store: *const rustls_root_cert_store,
435    ) -> *mut rustls_web_pki_server_cert_verifier_builder {
436        ffi_panic_boundary! {
437            let store = try_clone_arc!(store);
438            to_boxed_mut_ptr(Some(ServerCertVerifierBuilder {
439                provider: crypto_provider::get_default_or_install_from_crate_features(),
440                roots: store,
441                crls: Vec::default(),
442                revocation_depth: RevocationCheckDepth::Chain,
443                revocation_policy: UnknownStatusPolicy::Deny,
444                revocation_expiration_policy: ExpirationPolicy::Ignore,
445            }))
446        }
447    }
448
449    /// Create a `rustls_web_pki_server_cert_verifier_builder` using the specified
450    /// crypto provider. Caller owns the memory and may free it with
451    /// `rustls_web_pki_server_cert_verifier_builder_free`, regardless of whether
452    /// `rustls_web_pki_server_cert_verifier_builder_build` was called.
453    ///
454    /// Without further modification the builder will produce a server certificate verifier that
455    /// will require a server present a certificate that chains to one of the trust anchors
456    /// in the provided `rustls_root_cert_store`. The root cert store must not be empty.
457    ///
458    /// Revocation checking will not be performed unless
459    /// `rustls_web_pki_server_cert_verifier_builder_add_crl` is used to add certificate revocation
460    /// lists (CRLs) to the builder.  If CRLs are added, revocation checking will be performed
461    /// for the entire certificate chain unless
462    /// `rustls_web_pki_server_cert_verifier_only_check_end_entity_revocation` is used. Unknown
463    /// revocation status for certificates considered for revocation status will be treated as
464    /// an error unless `rustls_web_pki_server_cert_verifier_allow_unknown_revocation_status` is
465    /// used. Expired CRLs will not be treated as an error unless
466    /// `rustls_web_pki_server_cert_verifier_enforce_revocation_expiry` is used.
467    ///
468    /// This copies the contents of the `rustls_root_cert_store`. It does not take
469    /// ownership of the pointed-to data.
470    #[no_mangle]
471    pub extern "C" fn rustls_web_pki_server_cert_verifier_builder_new_with_provider(
472        provider: *const rustls_crypto_provider,
473        store: *const rustls_root_cert_store,
474    ) -> *mut rustls_web_pki_server_cert_verifier_builder {
475        ffi_panic_boundary! {
476            let provider = try_clone_arc!(provider);
477            let store = try_clone_arc!(store);
478            to_boxed_mut_ptr(Some(ServerCertVerifierBuilder {
479                provider: Some(provider),
480                roots: store,
481                crls: Vec::default(),
482                revocation_depth: RevocationCheckDepth::Chain,
483                revocation_policy: UnknownStatusPolicy::Deny,
484                revocation_expiration_policy: ExpirationPolicy::Ignore,
485            }))
486        }
487    }
488
489    /// Add one or more certificate revocation lists (CRLs) to the server certificate verifier
490    /// builder by reading the CRL content from the provided buffer of PEM encoded content.
491    ///
492    /// By default revocation checking will be performed on the entire certificate chain. To only
493    /// check the revocation status of the end entity certificate, use
494    /// `rustls_web_pki_server_cert_verifier_only_check_end_entity_revocation`.
495    ///
496    /// This function returns an error if the provided buffer is not valid PEM encoded content.
497    #[no_mangle]
498    pub extern "C" fn rustls_web_pki_server_cert_verifier_builder_add_crl(
499        builder: *mut rustls_web_pki_server_cert_verifier_builder,
500        crl_pem: *const u8,
501        crl_pem_len: size_t,
502    ) -> rustls_result {
503        ffi_panic_boundary! {
504            let server_verifier_builder = try_mut_from_ptr!(builder);
505            let server_verifier_builder = match server_verifier_builder {
506                None => return rustls_result::AlreadyUsed,
507                Some(v) => v,
508            };
509
510            let crls_der = match CertificateRevocationListDer::pem_slice_iter(try_slice!(
511                crl_pem,
512                crl_pem_len
513            ))
514            .collect::<Result<Vec<_>, _>>()
515            {
516                Ok(crls_der) => crls_der,
517                Err(_) => return rustls_result::CertificateRevocationListParseError,
518            };
519
520            if crls_der.is_empty() {
521                return rustls_result::CertificateRevocationListParseError;
522            }
523
524            server_verifier_builder.crls.extend(crls_der);
525
526            rustls_result::Ok
527        }
528    }
529
530    /// When CRLs are provided with `rustls_web_pki_server_cert_verifier_builder_add_crl`, only
531    /// check the revocation status of end entity certificates, ignoring any intermediate certificates
532    /// in the chain.
533    #[no_mangle]
534    pub extern "C" fn rustls_web_pki_server_cert_verifier_only_check_end_entity_revocation(
535        builder: *mut rustls_web_pki_server_cert_verifier_builder,
536    ) -> rustls_result {
537        ffi_panic_boundary! {
538            let server_verifier_builder = try_mut_from_ptr!(builder);
539            let server_verifier_builder = match server_verifier_builder {
540                None => return rustls_result::AlreadyUsed,
541                Some(v) => v,
542            };
543
544            server_verifier_builder.revocation_depth = RevocationCheckDepth::EndEntity;
545            rustls_result::Ok
546        }
547    }
548
549    /// When CRLs are provided with `rustls_web_pki_server_cert_verifier_builder_add_crl`, and it
550    /// isn't possible to determine the revocation status of a considered certificate, do not treat
551    /// it as an error condition.
552    ///
553    /// Overrides the default behavior where unknown revocation status is considered an error.
554    #[no_mangle]
555    pub extern "C" fn rustls_web_pki_server_cert_verifier_allow_unknown_revocation_status(
556        builder: *mut rustls_web_pki_server_cert_verifier_builder,
557    ) -> rustls_result {
558        ffi_panic_boundary! {
559            let server_verifier_builder = try_mut_from_ptr!(builder);
560            let server_verifier_builder = match server_verifier_builder {
561                None => return rustls_result::AlreadyUsed,
562                Some(v) => v,
563            };
564
565            server_verifier_builder.revocation_policy = UnknownStatusPolicy::Allow;
566            rustls_result::Ok
567        }
568    }
569
570    /// When CRLs are provided with `rustls_web_pki_server_cert_verifier_builder_add_crl`, and the
571    /// CRL nextUpdate field is in the past, treat it as an error condition.
572    ///
573    /// Overrides the default behavior where CRL expiration is ignored.
574    #[no_mangle]
575    pub extern "C" fn rustls_web_pki_server_cert_verifier_enforce_revocation_expiry(
576        builder: *mut rustls_web_pki_server_cert_verifier_builder,
577    ) -> rustls_result {
578        let server_verifier_builder = try_mut_from_ptr!(builder);
579        let server_verifier_builder = match server_verifier_builder {
580            None => return rustls_result::AlreadyUsed,
581            Some(v) => v,
582        };
583
584        server_verifier_builder.revocation_expiration_policy = ExpirationPolicy::Enforce;
585        rustls_result::Ok
586    }
587
588    /// Create a new server certificate verifier from the builder.
589    ///
590    /// The builder is consumed and cannot be used again, but must still be freed.
591    ///
592    /// The verifier can be used in several `rustls_client_config` instances and must be
593    /// freed by the application when no longer needed. See the documentation of
594    /// `rustls_web_pki_server_cert_verifier_builder_free` for details about lifetime.
595    #[no_mangle]
596    pub extern "C" fn rustls_web_pki_server_cert_verifier_builder_build(
597        builder: *mut rustls_web_pki_server_cert_verifier_builder,
598        verifier_out: *mut *mut rustls_server_cert_verifier,
599    ) -> rustls_result {
600        ffi_panic_boundary! {
601            let server_verifier_builder = try_mut_from_ptr!(builder);
602            let server_verifier_builder = try_take!(server_verifier_builder);
603            let verifier_out = try_mut_from_ptr_ptr!(verifier_out);
604
605            let builder = match server_verifier_builder.provider {
606                Some(provider) => WebPkiServerVerifier::builder_with_provider(
607                    server_verifier_builder.roots,
608                    provider,
609                ),
610                None => WebPkiServerVerifier::builder(server_verifier_builder.roots),
611            };
612
613            let mut builder = builder.with_crls(server_verifier_builder.crls);
614            match server_verifier_builder.revocation_depth {
615                RevocationCheckDepth::EndEntity => {
616                    builder = builder.only_check_end_entity_revocation()
617                }
618                RevocationCheckDepth::Chain => {}
619            }
620            match server_verifier_builder.revocation_policy {
621                UnknownStatusPolicy::Allow => builder = builder.allow_unknown_revocation_status(),
622                UnknownStatusPolicy::Deny => {}
623            }
624            match server_verifier_builder.revocation_expiration_policy {
625                ExpirationPolicy::Enforce => builder = builder.enforce_revocation_expiration(),
626                ExpirationPolicy::Ignore => {}
627            }
628
629            let verifier = match builder.build() {
630                Ok(v) => v,
631                Err(e) => return error::map_verifier_builder_error(e),
632            };
633
634            set_boxed_mut_ptr(verifier_out, verifier);
635
636            rustls_result::Ok
637        }
638    }
639
640    /// Free a `rustls_server_cert_verifier_builder` previously returned from
641    /// `rustls_server_cert_verifier_builder_new`.
642    ///
643    /// Calling with NULL is fine. Must not be called twice with the same value.
644    #[no_mangle]
645    pub extern "C" fn rustls_web_pki_server_cert_verifier_builder_free(
646        builder: *mut rustls_web_pki_server_cert_verifier_builder,
647    ) {
648        ffi_panic_boundary! {
649            free_box(builder);
650        }
651    }
652}
653
654/// A built server certificate verifier that can be provided to a `rustls_client_config_builder`
655/// with `rustls_client_config_builder_set_server_verifier`.
656//
657// Rustls' ConfigBuilder requires an `Arc<dyn ServerCertVerifier>` here, meaning we
658// must follow the pattern described in CONTRIBUTING.md[^0] for handling dynamically sized
659// types (DSTs) across the FFI boundary.
660// [^0]: <https://github.com/rustls/rustls-ffi/blob/main/CONTRIBUTING.md#dynamically-sized-types>
661pub struct rustls_server_cert_verifier {
662    _private: [u8; 0],
663}
664
665impl Castable for rustls_server_cert_verifier {
666    type Ownership = OwnershipBox;
667    type RustType = Arc<dyn ServerCertVerifier>;
668}
669
670impl rustls_server_cert_verifier {
671    /// Create a verifier that uses the default behavior for the current platform.
672    ///
673    /// This uses [`rustls-platform-verifier`][].
674    ///
675    /// The verifier can be used in several `rustls_client_config` instances and must be freed by
676    /// the application using `rustls_server_cert_verifier_free` when no longer needed.
677    ///
678    /// [`rustls-platform-verifier`]: https://github.com/rustls/rustls-platform-verifier
679    #[no_mangle]
680    pub extern "C" fn rustls_platform_server_cert_verifier(
681        verifier_out: *mut *mut rustls_server_cert_verifier,
682    ) -> rustls_result {
683        ffi_panic_boundary! {
684            let verifier_out = try_mut_from_ptr_ptr!(verifier_out);
685            let provider = match crypto_provider::get_default_or_install_from_crate_features() {
686                Some(provider) => provider,
687                None => return rustls_result::NoDefaultCryptoProvider,
688            };
689            let verifier = match rustls_platform_verifier::Verifier::new(provider) {
690                Ok(v) => v,
691                Err(e) => return error::map_error(e),
692            };
693            set_boxed_mut_ptr(verifier_out, Arc::new(verifier));
694            rustls_result::Ok
695        }
696    }
697
698    /// Create a verifier that uses the default behavior for the current platform.
699    ///
700    /// This uses [`rustls-platform-verifier`][] and the specified crypto provider.
701    ///
702    /// The verifier can be used in several `rustls_client_config` instances and must be freed by
703    /// the application using `rustls_server_cert_verifier_free` when no longer needed.
704    ///
705    /// If the initialization of `rustls-platform-verifier` fails, this function returns
706    /// `NULL`.
707    ///
708    /// [`rustls-platform-verifier`]: https://github.com/rustls/rustls-platform-verifier
709    // TODO: remove this function in the next breaking release
710    #[deprecated(note = "prefer to use rustls_platform_server_cert_verifier_try_with_provider")]
711    #[no_mangle]
712    pub extern "C" fn rustls_platform_server_cert_verifier_with_provider(
713        provider: *const rustls_crypto_provider,
714    ) -> *mut rustls_server_cert_verifier {
715        ffi_panic_boundary! {
716            let mut out = core::ptr::null_mut();
717            Self::rustls_platform_server_cert_verifier_try_with_provider(provider, &mut out);
718            out
719        }
720    }
721
722    /// Create a verifier that uses the default behavior for the current platform.
723    ///
724    /// This uses [`rustls-platform-verifier`][] and the specified crypto provider.
725    ///
726    /// If the initialization of `rustls-platform-verifier` fails, this function returns
727    /// an error and `NULL` is written to `verifier_out`.  Otherwise it fills in `verifier_out`
728    /// (whose ownership is transferred to the caller) and returns `RUSTLS_SUCCESS`.
729    ///
730    /// The verifier can be used in several `rustls_client_config` instances and must be freed by
731    /// the application using `rustls_server_cert_verifier_free` when no longer needed.
732    ///
733    /// [`rustls-platform-verifier`]: https://github.com/rustls/rustls-platform-verifier
734    #[no_mangle]
735    pub extern "C" fn rustls_platform_server_cert_verifier_try_with_provider(
736        provider: *const rustls_crypto_provider,
737        verifier_out: *mut *mut rustls_server_cert_verifier,
738    ) -> rustls_result {
739        ffi_panic_boundary! {
740            let verifier_out = try_mut_from_ptr_ptr!(verifier_out);
741            *verifier_out = core::ptr::null_mut();
742            let provider = try_clone_arc!(provider);
743            let verifier: Arc<dyn ServerCertVerifier> =
744                match rustls_platform_verifier::Verifier::new(provider) {
745                    Ok(v) => Arc::new(v),
746                    Err(e) => return error::map_error(e),
747                };
748            *verifier_out = to_boxed_mut_ptr(verifier);
749            rustls_result::Ok
750        }
751    }
752
753    /// Free a `rustls_server_cert_verifier` previously returned from
754    /// `rustls_server_cert_verifier_builder_build` or `rustls_platform_server_cert_verifier`.
755    ///
756    /// Calling with NULL is fine. Must not be called twice with the same value.
757    #[no_mangle]
758    pub extern "C" fn rustls_server_cert_verifier_free(verifier: *mut rustls_server_cert_verifier) {
759        ffi_panic_boundary! {
760            free_box(verifier);
761        }
762    }
763}