Skip to content

Commit c1b9cc3

Browse files
committed
Initial take on configuring client authentication certificates
This pretty much adapts the server-side support to the client.
1 parent bca9417 commit c1b9cc3

File tree

2 files changed

+84
-5
lines changed

2 files changed

+84
-5
lines changed

src/client.rs

+66-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
use std::ffi::OsStr;
1+
use std::convert::TryInto;
2+
use std::ffi::{CStr, OsStr};
23
use std::fs::File;
34
use std::io::BufReader;
45
use std::slice;
56
use std::sync::Arc;
6-
use std::{convert::TryInto, ffi::CStr};
77

88
use libc::{c_char, size_t};
99
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,
1212
};
1313

1414
use webpki::DNSNameRef;
1515

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};
1717
use crate::connection::{rustls_connection, Connection};
1818
use crate::enums::rustls_tls_version_from_u16;
1919
use crate::error::rustls_result::{InvalidParameter, NullParameter};
@@ -404,6 +404,67 @@ pub extern "C" fn rustls_client_config_builder_set_ciphersuites(
404404
}
405405
}
406406

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+
407468
/// "Free" a client_config_builder before transmogrifying it into a client_config.
408469
/// Normally builders are consumed to client_configs via `rustls_client_config_builder_build`
409470
/// and may not be free'd or otherwise used afterwards.

src/crustls.h

+18
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,24 @@ enum rustls_result rustls_client_config_builder_set_ciphersuites(struct rustls_c
750750
const struct rustls_supported_ciphersuite *const *ciphersuites,
751751
size_t len);
752752

753+
/**
754+
* Provide the configuration a list of certificates where the session
755+
* will select the first one that is compatible with the server's signature
756+
* verification capabilities. Clients that want to support both ECDSA and
757+
* RSA certificates will want the ECSDA to go first in the list.
758+
*
759+
* The built configuration will keep a reference to all certified keys
760+
* provided. The client may `rustls_certified_key_free()` afterwards
761+
* without the configuration losing them. The same certified key may also
762+
* be used in multiple configs.
763+
*
764+
* EXPERIMENTAL: installing a client authentication callback will replace any
765+
* configured certified keys and vice versa.
766+
*/
767+
enum rustls_result rustls_client_config_builder_set_certified_key(struct rustls_client_config_builder *builder,
768+
const struct rustls_certified_key *const *certified_keys,
769+
size_t certified_keys_len);
770+
753771
/**
754772
* "Free" a client_config_builder before transmogrifying it into a client_config.
755773
* Normally builders are consumed to client_configs via `rustls_client_config_builder_build`

0 commit comments

Comments
 (0)