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