|
1 |
| -use std::ffi::OsStr; |
| 1 | +use std::convert::TryInto; |
| 2 | +use std::ffi::{CStr, OsStr}; |
2 | 3 | use std::fs::File;
|
3 | 4 | use std::io::BufReader;
|
4 | 5 | use std::slice;
|
5 | 6 | use std::sync::Arc;
|
6 |
| -use std::{convert::TryInto, ffi::CStr}; |
7 | 7 |
|
8 | 8 | use libc::{c_char, size_t};
|
9 | 9 | use rustls::{
|
10 |
| - Certificate, ClientConfig, ClientSession, RootCertStore, ServerCertVerified, |
11 |
| - SupportedCipherSuite, TLSError, ALL_CIPHERSUITES, |
| 10 | + sign::CertifiedKey, Certificate, ClientConfig, ClientSession, ResolvesClientCert, |
| 11 | + RootCertStore, ServerCertVerified, SupportedCipherSuite, TLSError, ALL_CIPHERSUITES, |
12 | 12 | };
|
13 | 13 |
|
14 | 14 | use webpki::DNSNameRef;
|
15 | 15 |
|
16 |
| -use crate::cipher::{rustls_root_cert_store, rustls_supported_ciphersuite}; |
| 16 | +use crate::cipher::{rustls_certified_key, rustls_root_cert_store, rustls_supported_ciphersuite}; |
17 | 17 | use crate::connection::{rustls_connection, Connection};
|
18 | 18 | use crate::enums::rustls_tls_version_from_u16;
|
19 | 19 | use crate::error::rustls_result::{InvalidParameter, NullParameter};
|
@@ -404,6 +404,67 @@ pub extern "C" fn rustls_client_config_builder_set_ciphersuites(
|
404 | 404 | }
|
405 | 405 | }
|
406 | 406 |
|
| 407 | +/// Provide the configuration a list of certificates where the session |
| 408 | +/// will select the first one that is compatible with the server's signature |
| 409 | +/// verification capabilities. Clients that want to support both ECDSA and |
| 410 | +/// RSA certificates will want the ECSDA to go first in the list. |
| 411 | +/// |
| 412 | +/// The built configuration will keep a reference to all certified keys |
| 413 | +/// provided. The client may `rustls_certified_key_free()` afterwards |
| 414 | +/// without the configuration losing them. The same certified key may also |
| 415 | +/// be used in multiple configs. |
| 416 | +/// |
| 417 | +/// EXPERIMENTAL: installing a client authentication callback will replace any |
| 418 | +/// configured certified keys and vice versa. |
| 419 | +#[no_mangle] |
| 420 | +pub extern "C" fn rustls_client_config_builder_set_certified_key( |
| 421 | + builder: *mut rustls_client_config_builder, |
| 422 | + certified_keys: *const *const rustls_certified_key, |
| 423 | + certified_keys_len: size_t, |
| 424 | +) -> rustls_result { |
| 425 | + ffi_panic_boundary! { |
| 426 | + let config: &mut ClientConfig = try_mut_from_ptr!(builder); |
| 427 | + let keys_ptrs: &[*const rustls_certified_key] = try_slice!(certified_keys, certified_keys_len); |
| 428 | + let mut keys: Vec<Arc<CertifiedKey>> = Vec::new(); |
| 429 | + for &key_ptr in keys_ptrs { |
| 430 | + let key_ptr: &CertifiedKey = try_ref_from_ptr!(key_ptr); |
| 431 | + let certified_key: Arc<CertifiedKey> = unsafe { |
| 432 | + match (key_ptr as *const CertifiedKey).as_ref() { |
| 433 | + Some(c) => arc_with_incref_from_raw(c), |
| 434 | + None => return NullParameter, |
| 435 | + } |
| 436 | + }; |
| 437 | + keys.push(certified_key); |
| 438 | + } |
| 439 | + config.client_auth_cert_resolver = Arc::new(ResolvesClientCertFromChoices { keys }); |
| 440 | + rustls_result::Ok |
| 441 | + } |
| 442 | +} |
| 443 | + |
| 444 | +/// Always send the same client certificate. |
| 445 | +struct ResolvesClientCertFromChoices { |
| 446 | + keys: Vec<Arc<CertifiedKey>>, |
| 447 | +} |
| 448 | + |
| 449 | +impl ResolvesClientCert for ResolvesClientCertFromChoices { |
| 450 | + fn resolve( |
| 451 | + &self, |
| 452 | + _acceptable_issuers: &[&[u8]], |
| 453 | + sig_schemes: &[rustls::SignatureScheme], |
| 454 | + ) -> Option<rustls::sign::CertifiedKey> { |
| 455 | + for key in self.keys.iter() { |
| 456 | + if key.key.choose_scheme(sig_schemes).is_some() { |
| 457 | + return Some(key.as_ref().clone()); |
| 458 | + } |
| 459 | + } |
| 460 | + None |
| 461 | + } |
| 462 | + |
| 463 | + fn has_certs(&self) -> bool { |
| 464 | + !self.keys.is_empty() |
| 465 | + } |
| 466 | +} |
| 467 | + |
407 | 468 | /// "Free" a client_config_builder before transmogrifying it into a client_config.
|
408 | 469 | /// Normally builders are consumed to client_configs via `rustls_client_config_builder_build`
|
409 | 470 | /// and may not be free'd or otherwise used afterwards.
|
|
0 commit comments