use libc::size_t;
use std::convert::TryFrom;
use std::io::Cursor;
use std::ptr::null;
use std::slice;
use std::sync::Arc;
use rustls::server::{AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient};
use rustls::sign::CertifiedKey;
use rustls::{
Certificate, PrivateKey, RootCertStore, SupportedCipherSuite, ALL_CIPHER_SUITES,
DEFAULT_CIPHER_SUITES,
};
use rustls_pemfile::{certs, pkcs8_private_keys, rsa_private_keys};
use crate::error::rustls_result;
use crate::rslice::{rustls_slice_bytes, rustls_str};
use crate::{
ffi_panic_boundary, try_box_from_ptr, try_mut_from_ptr, try_ref_from_ptr, try_slice,
ArcCastPtr, BoxCastPtr, CastConstPtr, CastPtr,
};
use rustls_result::NullParameter;
use std::ops::Deref;
pub struct rustls_certificate {
_private: [u8; 0],
}
impl CastPtr for rustls_certificate {
type RustType = Certificate;
}
impl rustls_certificate {
#[no_mangle]
pub extern "C" fn rustls_certificate_get_der(
cert: *const rustls_certificate,
out_der_data: *mut *const u8,
out_der_len: *mut size_t,
) -> rustls_result {
ffi_panic_boundary! {
let cert = try_ref_from_ptr!(cert);
if out_der_data.is_null() || out_der_len.is_null() {
return NullParameter
}
let der = cert.as_ref();
unsafe {
*out_der_data = der.as_ptr();
*out_der_len = der.len();
}
rustls_result::Ok
}
}
}
pub struct rustls_supported_ciphersuite {
_private: [u8; 0],
}
impl CastPtr for rustls_supported_ciphersuite {
type RustType = SupportedCipherSuite;
}
impl rustls_supported_ciphersuite {
#[no_mangle]
pub extern "C" fn rustls_supported_ciphersuite_get_suite(
supported_ciphersuite: *const rustls_supported_ciphersuite,
) -> u16 {
let supported_ciphersuite = try_ref_from_ptr!(supported_ciphersuite);
match supported_ciphersuite {
rustls::SupportedCipherSuite::Tls12(sc) => &sc.common,
rustls::SupportedCipherSuite::Tls13(sc) => &sc.common,
}
.suite
.get_u16()
}
}
#[no_mangle]
pub extern "C" fn rustls_supported_ciphersuite_get_name(
supported_ciphersuite: *const rustls_supported_ciphersuite,
) -> rustls_str<'static> {
let supported_ciphersuite = try_ref_from_ptr!(supported_ciphersuite);
let s = supported_ciphersuite.suite().as_str().unwrap_or("");
match rustls_str::try_from(s) {
Ok(s) => s,
Err(_) => rustls_str::from_str_unchecked(""),
}
}
#[no_mangle]
pub extern "C" fn rustls_all_ciphersuites_len() -> usize {
ALL_CIPHER_SUITES.len()
}
#[no_mangle]
pub extern "C" fn rustls_all_ciphersuites_get_entry(
i: size_t,
) -> *const rustls_supported_ciphersuite {
match ALL_CIPHER_SUITES.get(i) {
Some(cs) => cs as *const SupportedCipherSuite as *const _,
None => null(),
}
}
#[no_mangle]
pub extern "C" fn rustls_default_ciphersuites_len() -> usize {
DEFAULT_CIPHER_SUITES.len()
}
#[no_mangle]
pub extern "C" fn rustls_default_ciphersuites_get_entry(
i: size_t,
) -> *const rustls_supported_ciphersuite {
match DEFAULT_CIPHER_SUITES.get(i) {
Some(cs) => cs as *const SupportedCipherSuite as *const _,
None => null(),
}
}
#[no_mangle]
pub static mut RUSTLS_ALL_CIPHER_SUITES: [*const rustls_supported_ciphersuite; 9] = [
&rustls::cipher_suite::TLS13_AES_256_GCM_SHA384 as *const SupportedCipherSuite as *const _,
&rustls::cipher_suite::TLS13_AES_128_GCM_SHA256 as *const SupportedCipherSuite as *const _,
&rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
as *const SupportedCipherSuite as *const _,
&rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
as *const SupportedCipherSuite as *const _,
];
#[no_mangle]
pub static RUSTLS_ALL_CIPHER_SUITES_LEN: usize = unsafe { RUSTLS_ALL_CIPHER_SUITES.len() };
#[no_mangle]
pub static mut RUSTLS_DEFAULT_CIPHER_SUITES: [*const rustls_supported_ciphersuite; 9] = [
&rustls::cipher_suite::TLS13_AES_256_GCM_SHA384 as *const SupportedCipherSuite as *const _,
&rustls::cipher_suite::TLS13_AES_128_GCM_SHA256 as *const SupportedCipherSuite as *const _,
&rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
as *const SupportedCipherSuite as *const _,
&rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 as *const SupportedCipherSuite
as *const _,
&rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
as *const SupportedCipherSuite as *const _,
];
#[no_mangle]
pub static RUSTLS_DEFAULT_CIPHER_SUITES_LEN: usize = unsafe { RUSTLS_DEFAULT_CIPHER_SUITES.len() };
#[cfg(test)]
mod tests {
use super::*;
use std::slice;
use std::str;
#[test]
fn all_cipher_suites_arrays() {
assert_eq!(RUSTLS_ALL_CIPHER_SUITES_LEN, ALL_CIPHER_SUITES.len());
for (original, ffi) in ALL_CIPHER_SUITES
.iter()
.zip(unsafe { RUSTLS_ALL_CIPHER_SUITES }.iter().copied())
{
let ffi_cipher_suite = try_ref_from_ptr!(ffi);
assert_eq!(original, ffi_cipher_suite);
}
}
#[test]
fn default_cipher_suites_arrays() {
assert_eq!(
RUSTLS_DEFAULT_CIPHER_SUITES_LEN,
DEFAULT_CIPHER_SUITES.len()
);
for (original, ffi) in DEFAULT_CIPHER_SUITES
.iter()
.zip(unsafe { RUSTLS_DEFAULT_CIPHER_SUITES }.iter().copied())
{
let ffi_cipher_suite = try_ref_from_ptr!(ffi);
assert_eq!(original, ffi_cipher_suite);
}
}
#[test]
fn ciphersuite_get_name() {
let suite = rustls_all_ciphersuites_get_entry(0);
let s = rustls_supported_ciphersuite_get_name(suite);
let want = "TLS13_AES_256_GCM_SHA384";
unsafe {
let got = str::from_utf8(slice::from_raw_parts(s.data as *const u8, s.len)).unwrap();
assert_eq!(want, got)
}
}
#[test]
fn test_all_ciphersuites_len() {
let len = rustls_all_ciphersuites_len();
assert!(len > 2);
}
}
pub struct rustls_certified_key {
_private: [u8; 0],
}
impl CastPtr for rustls_certified_key {
type RustType = CertifiedKey;
}
impl ArcCastPtr for rustls_certified_key {}
impl rustls_certified_key {
#[no_mangle]
pub extern "C" fn rustls_certified_key_build(
cert_chain: *const u8,
cert_chain_len: size_t,
private_key: *const u8,
private_key_len: size_t,
certified_key_out: *mut *const rustls_certified_key,
) -> rustls_result {
ffi_panic_boundary! {
let certified_key_out: &mut *const rustls_certified_key = unsafe {
match certified_key_out.as_mut() {
Some(c) => c,
None => return NullParameter,
}
};
let certified_key = match rustls_certified_key::certified_key_build(
cert_chain, cert_chain_len, private_key, private_key_len) {
Ok(key) => Box::new(key),
Err(rr) => return rr,
};
let certified_key = Arc::into_raw(Arc::new(*certified_key)) as *const _;
*certified_key_out = certified_key;
rustls_result::Ok
}
}
#[no_mangle]
pub extern "C" fn rustls_certified_key_get_certificate(
certified_key: *const rustls_certified_key,
i: size_t,
) -> *const rustls_certificate {
ffi_panic_boundary! {
let certified_key: &CertifiedKey = try_ref_from_ptr!(certified_key);
match certified_key.cert.get(i) {
Some(cert) => cert as *const Certificate as *const _,
None => null()
}
}
}
#[no_mangle]
pub extern "C" fn rustls_certified_key_clone_with_ocsp(
certified_key: *const rustls_certified_key,
ocsp_response: *const rustls_slice_bytes,
cloned_key_out: *mut *const rustls_certified_key,
) -> rustls_result {
ffi_panic_boundary! {
let cloned_key_out: &mut *const rustls_certified_key = unsafe {
match cloned_key_out.as_mut() {
Some(c) => c,
None => return NullParameter,
}
};
let certified_key: &CertifiedKey = try_ref_from_ptr!(certified_key);
let mut new_key = certified_key.deref().clone();
if !ocsp_response.is_null() {
let ocsp_slice = unsafe{ &*ocsp_response };
new_key.ocsp = Some(Vec::from(try_slice!(ocsp_slice.data, ocsp_slice.len)));
} else {
new_key.ocsp = None;
}
*cloned_key_out = ArcCastPtr::to_const_ptr(new_key);
rustls_result::Ok
}
}
#[no_mangle]
pub extern "C" fn rustls_certified_key_free(key: *const rustls_certified_key) {
ffi_panic_boundary! {
if key.is_null() {
return;
}
unsafe { drop(Arc::from_raw(key)) };
}
}
fn certified_key_build(
cert_chain: *const u8,
cert_chain_len: size_t,
private_key: *const u8,
private_key_len: size_t,
) -> Result<CertifiedKey, rustls_result> {
let mut cert_chain: &[u8] = unsafe {
if cert_chain.is_null() {
return Err(NullParameter);
}
slice::from_raw_parts(cert_chain, cert_chain_len as usize)
};
let private_key: &[u8] = unsafe {
if private_key.is_null() {
return Err(NullParameter);
}
slice::from_raw_parts(private_key, private_key_len as usize)
};
let mut private_keys: Vec<Vec<u8>> = match pkcs8_private_keys(&mut Cursor::new(private_key))
{
Ok(v) => v,
Err(_) => return Err(rustls_result::PrivateKeyParseError),
};
let private_key: PrivateKey = match private_keys.pop() {
Some(p) => PrivateKey(p),
None => {
private_keys = match rsa_private_keys(&mut Cursor::new(private_key)) {
Ok(v) => v,
Err(_) => return Err(rustls_result::PrivateKeyParseError),
};
let rsa_private_key: PrivateKey = match private_keys.pop() {
Some(p) => PrivateKey(p),
None => return Err(rustls_result::PrivateKeyParseError),
};
rsa_private_key
}
};
let signing_key = match rustls::sign::any_supported_type(&private_key) {
Ok(key) => key,
Err(_) => return Err(rustls_result::PrivateKeyParseError),
};
let parsed_chain: Vec<Certificate> = match certs(&mut cert_chain) {
Ok(v) => v.into_iter().map(Certificate).collect(),
Err(_) => return Err(rustls_result::CertificateParseError),
};
Ok(rustls::sign::CertifiedKey::new(parsed_chain, signing_key))
}
}
pub struct rustls_root_cert_store {
_private: [u8; 0],
}
impl CastPtr for rustls_root_cert_store {
type RustType = RootCertStore;
}
impl BoxCastPtr for rustls_root_cert_store {}
impl rustls_root_cert_store {
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_new() -> *mut rustls_root_cert_store {
ffi_panic_boundary! {
let store = rustls::RootCertStore::empty();
BoxCastPtr::to_mut_ptr(store)
}
}
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_add_pem(
store: *mut rustls_root_cert_store,
pem: *const u8,
pem_len: size_t,
strict: bool,
) -> rustls_result {
ffi_panic_boundary! {
let certs_pem: &[u8] = try_slice!(pem, pem_len);
let store: &mut RootCertStore = try_mut_from_ptr!(store);
let certs_der = match rustls_pemfile::certs(&mut Cursor::new(certs_pem)) {
Ok(vv) => vv,
Err(_) => return rustls_result::CertificateParseError,
};
let mut new_store = RootCertStore::empty();
let (parsed, rejected) = new_store.add_parsable_certificates(&certs_der);
if strict && (rejected > 0 || parsed == 0) {
return rustls_result::CertificateParseError;
}
store.roots.append(&mut new_store.roots);
rustls_result::Ok
}
}
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_free(store: *mut rustls_root_cert_store) {
ffi_panic_boundary! {
let store = try_box_from_ptr!(store);
drop(store)
}
}
}
pub struct rustls_client_cert_verifier {
_private: [u8; 0],
}
impl CastConstPtr for rustls_client_cert_verifier {
type RustType = AllowAnyAuthenticatedClient;
}
impl ArcCastPtr for rustls_client_cert_verifier {}
impl rustls_client_cert_verifier {
#[no_mangle]
pub extern "C" fn rustls_client_cert_verifier_new(
store: *const rustls_root_cert_store,
) -> *const rustls_client_cert_verifier {
let store: &RootCertStore = try_ref_from_ptr!(store);
return Arc::into_raw(AllowAnyAuthenticatedClient::new(store.clone())) as *const _;
}
#[no_mangle]
pub extern "C" fn rustls_client_cert_verifier_free(
verifier: *const rustls_client_cert_verifier,
) {
ffi_panic_boundary! {
if verifier.is_null() {
return;
}
unsafe { drop(Arc::from_raw(verifier)) };
}
}
}
pub struct rustls_client_cert_verifier_optional {
_private: [u8; 0],
}
impl CastConstPtr for rustls_client_cert_verifier_optional {
type RustType = AllowAnyAnonymousOrAuthenticatedClient;
}
impl ArcCastPtr for rustls_client_cert_verifier_optional {}
impl rustls_client_cert_verifier_optional {
#[no_mangle]
pub extern "C" fn rustls_client_cert_verifier_optional_new(
store: *const rustls_root_cert_store,
) -> *const rustls_client_cert_verifier_optional {
let store: &RootCertStore = try_ref_from_ptr!(store);
return Arc::into_raw(AllowAnyAnonymousOrAuthenticatedClient::new(store.clone()))
as *const _;
}
#[no_mangle]
pub extern "C" fn rustls_client_cert_verifier_optional_free(
verifier: *const rustls_client_cert_verifier_optional,
) {
ffi_panic_boundary! {
if verifier.is_null() {
return;
}
unsafe { drop(Arc::from_raw(verifier)) };
}
}
}