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}