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}