From 1edb6f682eaa728871e39aa41735a668fcc7447c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 6 Nov 2016 12:16:44 -0800 Subject: [PATCH] Support client CA advertisement --- openssl-sys/src/lib.rs | 2 ++ openssl-sys/src/ossl10x.rs | 5 +++++ openssl-sys/src/ossl110.rs | 1 + openssl/src/ssl/connector.rs | 1 - openssl/src/ssl/mod.rs | 13 ++++++++++++- openssl/src/ssl/tests/mod.rs | 11 ++++++++++- openssl/src/x509/mod.rs | 17 +++++++++++++++++ 7 files changed, 47 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 13532477..496cc379 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1580,6 +1580,7 @@ extern { pub fn SSL_get_privatekey(ssl: *mut SSL) -> *mut EVP_PKEY; #[cfg(not(ossl101))] pub fn SSL_get_privatekey(ssl: *const SSL) -> *mut EVP_PKEY; + pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; #[cfg(not(osslconf = "OPENSSL_NO_COMP"))] pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; @@ -1610,6 +1611,7 @@ extern { pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int; pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int; pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int; + pub fn SSL_CTX_set_client_CA_list(ctx: *mut SSL_CTX, list: *mut stack_st_X509_NAME); #[cfg(not(ossl101))] pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 2b066446..0cc75fca 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -16,6 +16,11 @@ pub struct stack_st_X509 { pub stack: _STACK, } +#[repr(C)] +pub struct stack_st_X509_NAME { + pub stack: _STACK, +} + #[repr(C)] pub struct stack_st_X509_ATTRIBUTE { pub stack: _STACK, diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index a2259fc6..e8d62d73 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -18,6 +18,7 @@ pub enum stack_st_GENERAL_NAME {} pub enum stack_st_OPENSSL_STRING {} pub enum stack_st_void {} pub enum stack_st_X509 {} +pub enum stack_st_X509_NAME {} pub enum stack_st_X509_ATTRIBUTE {} pub enum stack_st_X509_EXTENSION {} pub enum X509 {} diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 0d92529d..55177767 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -277,7 +277,6 @@ mod verify { use nid; use x509::{X509StoreContextRef, X509Ref, X509NameRef, GeneralName}; use stack::Stack; - use types::OpenSslTypeRef; pub fn verify_callback(domain: &str, preverify_ok: bool, diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 5c41f6ea..1e7efc63 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -93,13 +93,14 @@ use std::sync::Mutex; use {init, cvt, cvt_p}; use dh::DhRef; use ec_key::EcKeyRef; -use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError}; +use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; #[cfg(any(ossl102, ossl110))] use verify::X509VerifyParamRef; use pkey::PKeyRef; use error::ErrorStack; use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; +use stack::Stack; mod error; mod connector; @@ -542,6 +543,16 @@ impl SslContextBuilder { } } + /// Sets the list of CAs sent to the client. + /// + /// The CA certificates must still be added to the trust root. + pub fn set_client_ca_list(&mut self, list: Stack) { + unsafe { + ffi::SSL_CTX_set_client_CA_list(self.as_ptr(), list.as_ptr()); + mem::forget(list); + } + } + /// Set the context identifier for sessions /// /// This value identifies the server's session cache to a clients, telling them when they're diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index a84f6b25..146d0806 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -20,7 +20,7 @@ use ssl::SSL_VERIFY_PEER; use ssl::{SslMethod, HandshakeError}; use ssl::{SslContext, SslStream, Ssl, ShutdownResult, SslConnectorBuilder, SslAcceptorBuilder, Error}; -use x509::{X509StoreContext, X509, X509_FILETYPE_PEM}; +use x509::{X509StoreContext, X509, X509Name, X509_FILETYPE_PEM}; #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] use x509::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; use pkey::PKey; @@ -1184,6 +1184,15 @@ fn shutdown() { assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received); } +#[test] +fn client_ca_list() { + let names = X509Name::load_client_ca_file("test/root-ca.pem").unwrap(); + assert_eq!(names.len(), 1); + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_client_ca_list(names); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index eb517f80..e98e6006 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -6,6 +6,7 @@ use std::error::Error; use std::ffi::{CStr, CString}; use std::fmt; use std::mem; +use std::path::Path; use std::ptr; use std::slice; use std::str; @@ -498,6 +499,22 @@ impl Stackable for X509 { type_!(X509Name, X509NameRef, ffi::X509_NAME, ffi::X509_NAME_free); +impl X509Name { + /// Loads subject names from a file containing PEM-formatted certificates. + /// + /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`. + pub fn load_client_ca_file>(file: P) -> Result, ErrorStack> { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { + cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) + } + } +} + +impl Stackable for X509Name { + type StackType = ffi::stack_st_X509_NAME; +} + impl X509NameRef { pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> { X509NameEntries {