diff --git a/src/cert_chain.rs b/src/cert_chain.rs index 2781e0f..a700968 100644 --- a/src/cert_chain.rs +++ b/src/cert_chain.rs @@ -42,7 +42,8 @@ impl CertChainContext { } None } - + + /// Retrieves the specified chain from the context. pub fn get_chain(&self, index :usize) -> Option { let cert_chain = unsafe { let cert_chain = *self.0; @@ -67,7 +68,7 @@ impl CertChainContext { } } -/// A (simple) certificate chain +/// A (simple) certificate chain pub struct CertChain(winapi::PCERT_SIMPLE_CHAIN, CertChainContext); impl CertChain { diff --git a/src/cert_context.rs b/src/cert_context.rs index 48c0be9..ff2d8e9 100644 --- a/src/cert_context.rs +++ b/src/cert_context.rs @@ -9,8 +9,9 @@ use std::slice; use crypt32; use winapi; -use {Inner, KeyHandlePriv}; -use key_handle::KeyHandle; +use Inner; +use ncrypt_key::NcryptKey; +use crypt_prov::{CryptProv, ProviderType}; // FIXME https://github.com/retep998/winapi-rs/pull/318 const CRYPT_ACQUIRE_COMPARE_KEY_FLAG: winapi::DWORD = 0x4; @@ -20,13 +21,6 @@ const CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG: winapi::DWORD = 0x10000; // FIXME const CRYPT_STRING_BASE64HEADER: winapi::DWORD = 0x0; -/// Wrapper of a winapi certificate, or a `PCCERT_CONTEXT`. -#[derive(Debug)] -pub struct CertContext(winapi::PCCERT_CONTEXT); - -unsafe impl Sync for CertContext {} -unsafe impl Send for CertContext {} - /// A supported hashing algorithm pub struct HashAlgorithm(winapi::DWORD, usize); @@ -53,6 +47,29 @@ impl HashAlgorithm { } } +/// Wrapper of a winapi certificate, or a `PCCERT_CONTEXT`. +#[derive(Debug)] +pub struct CertContext(winapi::PCCERT_CONTEXT); + +unsafe impl Sync for CertContext {} +unsafe impl Send for CertContext {} + +impl Drop for CertContext { + fn drop(&mut self) { + unsafe { + crypt32::CertFreeCertificateContext(self.0); + } + } +} + +impl Clone for CertContext { + fn clone(&self) -> CertContext { + unsafe { CertContext(crypt32::CertDuplicateCertificateContext(self.0)) } + } +} + +inner!(CertContext, winapi::PCCERT_CONTEXT); + impl CertContext { /// Decodes a DER-formatted X509 certificate. pub fn new(data: &[u8]) -> io::Result { @@ -199,6 +216,18 @@ impl CertContext { } } + /// Returns a builder used to set the private key associated with this certificate. + pub fn set_key_prov_info<'a>(&'a self) -> SetKeyProvInfo<'a> { + SetKeyProvInfo { + cert: self, + container: None, + provider: None, + type_: 0, + flags: 0, + key_spec: 0, + } + } + fn get_encoded_bytes(&self) -> &[u8] { unsafe { let cert_ctx = *self.0; @@ -310,7 +339,7 @@ impl<'a> AcquirePrivateKeyOptions<'a> { } /// Acquires the private key handle. - pub fn acquire(&self) -> io::Result { + pub fn acquire(&self) -> io::Result { unsafe { let flags = self.flags | CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG; let mut handle = 0; @@ -326,36 +355,136 @@ impl<'a> AcquirePrivateKeyOptions<'a> { return Err(io::Error::last_os_error()); } assert!(free == winapi::TRUE); - Ok(KeyHandle::new(handle, spec)) + if spec & winapi::CERT_NCRYPT_KEY_SPEC != 0 { + Ok(PrivateKey::NcryptKey(NcryptKey::from_inner(handle))) + } else { + Ok(PrivateKey::CryptProv(CryptProv::from_inner(handle))) + } } } } -impl Clone for CertContext { - fn clone(&self) -> CertContext { - unsafe { CertContext(crypt32::CertDuplicateCertificateContext(self.0)) } - } +/// The private key associated with a certificate context. +pub enum PrivateKey { + /// A CryptoAPI provider. + CryptProv(CryptProv), + /// A CNG provider. + NcryptKey(NcryptKey), } -impl Drop for CertContext { - fn drop(&mut self) { +/// A builder used to set the private key associated with a certificate. +pub struct SetKeyProvInfo<'a> { + cert: &'a CertContext, + container: Option>, + provider: Option>, + type_: winapi::DWORD, + flags: winapi::DWORD, + key_spec: winapi::DWORD, +} + +impl<'a> SetKeyProvInfo<'a> { + /// The name of the key container. + /// + /// If `type_` is not provided, this specifies the name of the key withing + /// the CNG key storage provider. + pub fn container(&mut self, container: &str) -> &mut SetKeyProvInfo<'a> { + self.container = Some(container.encode_utf16().chain(Some(0)).collect()); + self + } + + /// The name of the CSP. + /// + /// If `type_` is not provided, this contains the name of the CNG key + /// storage provider. + pub fn provider(&mut self, provider: &str) -> &mut SetKeyProvInfo<'a> { + self.provider = Some(provider.encode_utf16().chain(Some(0)).collect()); + self + } + + /// Sets the CSP type. + /// + /// If not provided, the key container is one of the CNG key storage + /// providers. + pub fn type_(&mut self, type_: ProviderType) -> &mut SetKeyProvInfo<'a> { + self.type_ = type_.as_raw(); + self + } + + /// If set, the handle to the key provider can be kept open for subsequent + /// calls to cryptographic functions. + pub fn keep_open(&mut self, keep_open: bool) -> &mut SetKeyProvInfo<'a> { + self.flag(winapi::CERT_SET_KEY_PROV_HANDLE_PROP_ID, keep_open) + } + + /// If set, the key container contains machine keys. + pub fn machine_keyset(&mut self, machine_keyset: bool) -> &mut SetKeyProvInfo<'a> { + self.flag(winapi::CRYPT_MACHINE_KEYSET, machine_keyset) + } + + /// If set, the key container will attempt to open keys without any user + /// interface prompts. + pub fn silent(&mut self, silent: bool) -> &mut SetKeyProvInfo<'a> { + self.flag(winapi::CRYPT_SILENT, silent) + } + + fn flag(&mut self, flag: winapi::DWORD, on: bool) -> &mut SetKeyProvInfo<'a> { + if on { + self.flags |= flag; + } else { + self.flags &= !flag; + } + self + } + + /// The specification of the private key to retrieve. + pub fn key_spec(&mut self, key_spec: KeySpec) -> &mut SetKeyProvInfo<'a> { + self.key_spec = key_spec.0; + self + } + + /// Sets the private key for this certificate. + pub fn set(&mut self) -> io::Result<()> { unsafe { - crypt32::CertFreeCertificateContext(self.0); + let container = self.container.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); + let provider = self.provider.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); + + let info = winapi::CRYPT_KEY_PROV_INFO { + pwszContainerName: container as *mut _, + pwszProvName: provider as *mut _, + dwProvType: self.type_, + dwFlags: self.flags, + cProvParam: 0, + rgProvParam: ptr::null_mut(), + dwKeySpec: self.key_spec, + }; + + let res = + crypt32::CertSetCertificateContextProperty(self.cert.0, + winapi::CERT_KEY_PROV_INFO_PROP_ID, + 0, + &info as *const _ as *const _); + if res == winapi::TRUE { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } } } } -impl Inner for CertContext { - unsafe fn from_inner(t: winapi::PCCERT_CONTEXT) -> CertContext { - CertContext(t) - } +/// The specification of a private key. +#[derive(Copy, Clone)] +pub struct KeySpec(winapi::DWORD); - fn as_inner(&self) -> winapi::PCCERT_CONTEXT { - self.0 +impl KeySpec { + /// A key used to encrypt/decrypt session keys. + pub fn key_exchange() -> KeySpec { + KeySpec(winapi::AT_KEYEXCHANGE) } - fn get_mut(&mut self) -> &mut winapi::PCCERT_CONTEXT { - &mut self.0 + /// A key used to create and verify digital signatures. + pub fn signature() -> KeySpec { + KeySpec(winapi::AT_SIGNATURE) } } @@ -383,16 +512,17 @@ mod test { let hash = der.fingerprint(HashAlgorithm::sha1()).unwrap(); assert_eq!(hash, vec![‎ - 0x5b, 0x77, 0x9a, 0xc3, 0x23, 0xdc, 0xc4, 0xff, 0xd8, 0xf1, - 0x89, 0x5e, 0xea, 0x73, 0x96, 0x79, 0x84, 0xbd, 0xf6, 0x86 + 0x59, 0x17, 0x2D, 0x93, 0x13, 0xE8, 0x44, 0x59, 0xBC, 0xFF, + 0x27, 0xF9, 0x67, 0xE7, 0x9E, 0x6E, 0x92, 0x17, 0xE5, 0x84 ]); assert_eq!(hash, pem.fingerprint(HashAlgorithm::sha1()).unwrap()); - + let hash = der.fingerprint(HashAlgorithm::sha256()).unwrap(); assert_eq!(hash, vec![ - 0x9c, 0xf3, 0x6b, 0x55, 0x56, 0xde, 0x20, 0xd9, 0x69, 0xc0, 0xdd, 0x8f, - 0xca, 0xda, 0xda, 0x9b, 0xb8, 0x51, 0x9, 0x9f, 0x86, 0x8f, 0x85, 0x5d, - 0x90, 0x81, 0x73, 0xb5, 0x7a, 0xe0, 0x5a, 0xdd + 0x47, 0x12, 0xB9, 0x39, 0xFB, 0xCB, 0x42, 0xA6, 0xB5, 0x10, + 0x1B, 0x42, 0x13, 0x9A, 0x25, 0xB1, 0x4F, 0x81, 0xB4, 0x18, + 0xFA, 0xCA, 0xBD, 0x37, 0x87, 0x46, 0xF1, 0x2F, 0x85, 0xCC, + 0x65, 0x44 ]); assert_eq!(hash, pem.fingerprint(HashAlgorithm::sha256()).unwrap()); } diff --git a/src/cert_store.rs b/src/cert_store.rs index 6cbf2b5..587b3a8 100644 --- a/src/cert_store.rs +++ b/src/cert_store.rs @@ -45,19 +45,7 @@ impl Clone for CertStore { } } -impl Inner for CertStore { - unsafe fn from_inner(t: winapi::HCERTSTORE) -> CertStore { - CertStore(t) - } - - fn as_inner(&self) -> winapi::HCERTSTORE { - self.0 - } - - fn get_mut(&mut self) -> &mut winapi::HCERTSTORE { - &mut self.0 - } -} +inner!(CertStore, winapi::HCERTSTORE); /// Argument to the `add_cert` function indicating how a certificate should be /// added to a `CertStore`. diff --git a/src/crypt_key.rs b/src/crypt_key.rs new file mode 100644 index 0000000..8e061a9 --- /dev/null +++ b/src/crypt_key.rs @@ -0,0 +1,16 @@ +//! CryptoAPI private keys. +use advapi32; +use winapi; + +/// A handle to a key. +pub struct CryptKey(winapi::HCRYPTKEY); + +impl Drop for CryptKey { + fn drop(&mut self) { + unsafe { + advapi32::CryptDestroyKey(self.0); + } + } +} + +inner!(CryptKey, winapi::HCRYPTKEY); diff --git a/src/crypt_prov.rs b/src/crypt_prov.rs new file mode 100644 index 0000000..162b103 --- /dev/null +++ b/src/crypt_prov.rs @@ -0,0 +1,225 @@ +//! CryptoAPI key providers. +use advapi32; +use crypt32; +use kernel32; +use std::io; +use std::ptr; +use winapi; + +use Inner; +use crypt_key::CryptKey; + +/// A CryptoAPI handle to a provider of a key. +pub struct CryptProv(winapi::HCRYPTPROV); + +impl Drop for CryptProv { + fn drop(&mut self) { + unsafe { + advapi32::CryptReleaseContext(self.0, 0); + } + } +} + +inner!(CryptProv, winapi::HCRYPTPROV); + +impl CryptProv { + /// Imports a key into this provider. + pub fn import<'a>(&'a mut self) -> ImportOptions<'a> { + ImportOptions { + prov: self, + flags: 0, + } + } +} + +/// A builder for `CryptProv`s. +pub struct AcquireOptions { + container: Option>, + provider: Option>, + flags: winapi::DWORD, +} + +impl AcquireOptions { + /// Returns a new builder with default settings. + pub fn new() -> AcquireOptions { + AcquireOptions { + container: None, + provider: None, + flags: 0, + } + } + + /// Sets the name for this key container. + /// + /// This should not be set if `verify_context` is set. + pub fn container(&mut self, container: &str) -> &mut AcquireOptions { + self.container = Some(container.encode_utf16().chain(Some(0)).collect()); + self + } + + /// Sets the name of the CSP to be used. + pub fn provider(&mut self, provider: &str) -> &mut AcquireOptions { + self.provider = Some(provider.encode_utf16().chain(Some(0)).collect()); + self + } + + /// If set, private keys will not be accessible or persisted. + pub fn verify_context(&mut self, verify_context: bool) -> &mut AcquireOptions { + self.flag(winapi::CRYPT_VERIFYCONTEXT, verify_context) + } + + /// If set, the container will be created. + pub fn new_keyset(&mut self, new_keyset: bool) -> &mut AcquireOptions { + self.flag(winapi::CRYPT_NEWKEYSET, new_keyset) + } + + /// If set, the container will be stored as a machine rather than user keys. + pub fn machine_keyset(&mut self, machine_keyset: bool) -> &mut AcquireOptions { + self.flag(winapi::CRYPT_MACHINE_KEYSET, machine_keyset) + } + + /// If set, an error will be returned if user intervention is required + /// rather than displaying a dialog. + pub fn silent(&mut self, silent: bool) -> &mut AcquireOptions { + self.flag(winapi::CRYPT_SILENT, silent) + } + + fn flag(&mut self, flag: winapi::DWORD, on: bool) -> &mut AcquireOptions { + if on { + self.flags |= flag; + } else { + self.flags &= !flag; + } + + self + } + + /// Acquires a container. + pub fn acquire(&self, type_: ProviderType) -> io::Result { + unsafe { + let container = self.container.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); + let provider = self.provider.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); + + let mut prov = 0; + let res = advapi32::CryptAcquireContextW(&mut prov, + container as *mut _, + provider as *mut _, + type_.0, + self.flags); + if res == winapi::TRUE { + Ok(CryptProv(prov)) + } else { + Err(io::Error::last_os_error()) + } + } + } +} + +/// An identifier of the type of cryptography provider to be used with a +/// container. +#[derive(Copy, Clone)] +pub struct ProviderType(winapi::DWORD); + +#[allow(missing_docs)] +impl ProviderType { + pub fn rsa_full() -> ProviderType { + ProviderType(winapi::PROV_RSA_FULL) + } + + pub fn rsa_aes() -> ProviderType { + ProviderType(winapi::PROV_RSA_AES) + } + + pub fn rsa_sig() -> ProviderType { + ProviderType(winapi::PROV_RSA_SIG) + } + + pub fn rsa_schannel() -> ProviderType { + ProviderType(winapi::PROV_RSA_SCHANNEL) + } + + pub fn dss() -> ProviderType { + ProviderType(winapi::PROV_DSS) + } + + pub fn dss_dh() -> ProviderType { + ProviderType(winapi::PROV_DSS_DH) + } + + pub fn dh_schannel() -> ProviderType { + ProviderType(winapi::PROV_DH_SCHANNEL) + } + + pub fn fortezza() -> ProviderType { + ProviderType(winapi::PROV_FORTEZZA) + } + + pub fn ms_exchange() -> ProviderType { + ProviderType(winapi::PROV_MS_EXCHANGE) + } + + pub fn ssl() -> ProviderType { + ProviderType(winapi::PROV_SSL) + } + + pub fn as_raw(&self) -> winapi::DWORD { + self.0 + } +} + +/// A builder for key imports. +pub struct ImportOptions<'a> { + prov: &'a mut CryptProv, + flags: winapi::DWORD, +} + +impl<'a> ImportOptions<'a> { + /// Imports a DER-encoded private key. + pub fn import(&mut self, der: &[u8]) -> io::Result { + unsafe { + assert!(der.len() <= winapi::DWORD::max_value() as usize); + let mut buf = ptr::null_mut(); + let mut len = 0; + let res = crypt32::CryptDecodeObjectEx(winapi::X509_ASN_ENCODING | + winapi::PKCS_7_ASN_ENCODING, + winapi::PKCS_RSA_PRIVATE_KEY, + der.as_ptr(), + der.len() as winapi::DWORD, + winapi::CRYPT_DECODE_ALLOC_FLAG, + ptr::null_mut(), + &mut buf as *mut _ as *mut winapi::c_void, + &mut len); + if res == winapi::FALSE { + return Err(io::Error::last_os_error()); + } + + let mut key = 0; + let res = advapi32::CryptImportKey(self.prov.0, buf, len, 0, self.flags, &mut key); + kernel32::LocalFree(buf as *mut _); + + if res == winapi::TRUE { + Ok(CryptKey::from_inner(key)) + } else { + Err(io::Error::last_os_error()) + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn rsa_key() { + let key = include_bytes!("../test/key.key"); + + let mut context = AcquireOptions::new() + .verify_context(true) + .acquire(ProviderType::rsa_full()) + .unwrap(); + context.import() + .import(key) + .unwrap(); + } +} diff --git a/src/key_handle.rs b/src/key_handle.rs index 5a2e11f..7e458f2 100644 --- a/src/key_handle.rs +++ b/src/key_handle.rs @@ -1,38 +1,5 @@ -//! Private keys. +//! Deprecated. +#![deprecated(note = "use cert_context::PrivateKey", since = "0.1.5")] -use advapi32; -use winapi; - -use KeyHandlePriv; - -/// A handle to a private key. -pub struct KeyHandle { - handle: winapi::HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, - spec: winapi::DWORD, -} - -// FIXME https://github.com/retep998/winapi-rs/pull/319 -extern "system" { - fn NCryptFreeObject(handle: winapi::NCRYPT_HANDLE) -> winapi::SECURITY_STATUS; -} - -impl Drop for KeyHandle { - fn drop(&mut self) { - unsafe { - if self.spec == winapi::CERT_NCRYPT_KEY_SPEC { - NCryptFreeObject(self.handle); - } else { - advapi32::CryptReleaseContext(self.handle, 0); - } - } - } -} - -impl KeyHandlePriv for KeyHandle { - fn new(handle: winapi::HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, spec: winapi::DWORD) -> KeyHandle { - KeyHandle { - handle: handle, - spec: spec, - } - } -} +#[deprecated(note = "use cert_context::PrivateKey", since = "0.1.5")] +pub use cert_context::PrivateKey as KeyHandle; diff --git a/src/lib.rs b/src/lib.rs index 0934066..d2b7efa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,13 +14,32 @@ extern crate lazy_static; use std::ptr; -use key_handle::KeyHandle; +macro_rules! inner { + ($t:path, $raw:ty) => { + impl ::Inner<$raw> for $t { + unsafe fn from_inner(t: $raw) -> Self { + $t(t) + } + + fn as_inner(&self) -> $raw { + self.0 + } + + fn get_mut(&mut self) -> &mut $raw { + &mut self.0 + } + } + } +} pub mod cert_chain; pub mod cert_context; pub mod cert_store; +pub mod crypt_key; +pub mod crypt_prov; /* pub */ mod ctl_context; pub mod key_handle; +pub mod ncrypt_key; pub mod schannel_cred; pub mod tls_stream; @@ -48,10 +67,6 @@ trait Inner { fn get_mut(&mut self) -> &mut T; } -trait KeyHandlePriv { - fn new(handle: winapi::HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, spec: winapi::DWORD) -> KeyHandle; -} - unsafe fn secbuf(buftype: winapi::c_ulong, bytes: Option<&mut [u8]>) -> winapi::SecBuffer { let (ptr, len) = match bytes { diff --git a/src/ncrypt_key.rs b/src/ncrypt_key.rs new file mode 100644 index 0000000..5d453ac --- /dev/null +++ b/src/ncrypt_key.rs @@ -0,0 +1,20 @@ +//! CNG private keys. +use winapi; + +// FIXME https://github.com/retep998/winapi-rs/pull/319 +extern "system" { + fn NCryptFreeObject(handle: winapi::NCRYPT_HANDLE) -> winapi::SECURITY_STATUS; +} + +/// A CNG handle to a key. +pub struct NcryptKey(winapi::NCRYPT_KEY_HANDLE); + +impl Drop for NcryptKey { + fn drop(&mut self) { + unsafe { + NCryptFreeObject(self.0); + } + } +} + +inner!(NcryptKey, winapi::NCRYPT_KEY_HANDLE); diff --git a/src/test.rs b/src/test.rs index 2dbeffd..7a597a1 100644 --- a/src/test.rs +++ b/src/test.rs @@ -12,7 +12,8 @@ use std::thread; use winapi; use Inner; -use cert_context::{CertContext, HashAlgorithm}; +use crypt_prov::{AcquireOptions, ProviderType}; +use cert_context::{CertContext, KeySpec, HashAlgorithm}; use cert_store::{CertStore, Memory, CertAdd}; use schannel_cred::{Direction, Protocol, Algorithm, SchannelCred}; use tls_stream::{self, HandshakeError}; @@ -558,3 +559,68 @@ fn accept_one_byte_at_a_time() { t.join().unwrap(); } + +#[test] +fn split_cert_key() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + let t = thread::spawn(move || { + let cert = include_bytes!("../test/cert.der"); + let mut store = Memory::new().unwrap(); + store.add_encoded_certificate(cert).unwrap(); + let store = store.into_store(); + + let stream = TcpStream::connect(&addr).unwrap(); + let creds = SchannelCred::builder() + .acquire(Direction::Outbound).unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("foobar.com") + .cert_store(store) + .connect(creds, stream) + .unwrap(); + stream.write_all(&[1, 2, 3, 4]).unwrap(); + stream.flush().unwrap(); + assert_eq!(stream.read(&mut [0; 1024]).unwrap(), 4); + stream.shutdown().unwrap(); + }); + + let cert = include_bytes!("../test/cert.der"); + let cert = CertContext::new(cert).unwrap(); + + let mut options = AcquireOptions::new(); + options.container("schannel-test"); + let type_ = ProviderType::rsa_full(); + + let mut container = match options.acquire(type_) { + Ok(container) => container, + Err(_) => options.new_keyset(true).acquire(type_).unwrap(), + }; + let key = include_bytes!("../test/key.key"); + container.import() + .import(key) + .unwrap(); + + cert.set_key_prov_info() + .container("schannel-test") + .type_(type_) + .keep_open(true) + .key_spec(KeySpec::key_exchange()) + .set() + .unwrap(); + + let stream = listener.accept().unwrap().0; + let creds = SchannelCred::builder() + .cert(cert) + .acquire(Direction::Inbound) + .unwrap(); + let mut stream = tls_stream::Builder::new() + .accept(creds, stream) + .unwrap(); + assert_eq!(stream.read(&mut [0; 1024]).unwrap(), 4); + stream.write_all(&[1, 2, 3, 4]).unwrap(); + stream.flush().unwrap(); + let mut buf = [0; 1]; + assert_eq!(stream.read(&mut buf).unwrap(), 0); + + t.join().unwrap(); +} diff --git a/src/tls_stream.rs b/src/tls_stream.rs index 8252114..14f0a83 100644 --- a/src/tls_stream.rs +++ b/src/tls_stream.rs @@ -35,7 +35,6 @@ pub struct Builder { domain: Option>, verify_callback: Option io::Result<()> + Sync + Send>>, cert_store: Option, - accept: bool, } impl Builder { @@ -55,11 +54,11 @@ impl Builder { /// Set a verification callback to be used for connections created with this `Builder`. /// - /// The callback is provided with an io::Result indicating if the (pre)validation was - /// successful. The Ok() variant indicates a successful validation while the Err() variant - /// contains the errorcode returned from the internal verification process. + /// The callback is provided with an io::Result indicating if the (pre)validation was + /// successful. The Ok() variant indicates a successful validation while the Err() variant + /// contains the errorcode returned from the internal verification process. /// The validated certificate, is accessible through the second argument of the closure. - pub fn verify_callback(&mut self, callback: F) -> &mut Builder + pub fn verify_callback(&mut self, callback: F) -> &mut Builder where F: Fn(CertValidationResult) -> io::Result<()> + 'static + Sync + Send { self.verify_callback = Some(Arc::new(callback)); @@ -207,16 +206,15 @@ pub enum HandshakeError { Interrupted(MidHandshakeTlsStream), } -/// A struct used to wrap various cert chain validation results for callback processing. +/// A struct used to wrap various cert chain validation results for callback processing. pub struct CertValidationResult { - chain :CertChainContext, - res :i32, - chain_index :i32, - element_index :i32, + chain: CertChainContext, + res: i32, + chain_index: i32, + element_index: i32, } impl CertValidationResult { - /// Returns the certificate that failed validation if applicable pub fn failed_certificate(&self) -> Option { if let Some(cert_chain) = self.chain.get_chain(self.chain_index as usize) { @@ -224,12 +222,13 @@ impl CertValidationResult { } None } - - // Returns the final certificate chain in the certificate context if applicable + + /// Returns the final certificate chain in the certificate context if applicable pub fn chain(&self) -> Option { self.chain.final_chain() } - + + /// Returns the result of the built-in certificate verification process. pub fn result(&self) -> io::Result<()> { if self.res as u32 != winapi::ERROR_SUCCESS { Err(io::Error::from_raw_os_error(self.res)) diff --git a/test/cert.der b/test/cert.der index c414ffa..e1f964d 100644 Binary files a/test/cert.der and b/test/cert.der differ diff --git a/test/cert.pem b/test/cert.pem index 8cbdf50..032fe60 100644 --- a/test/cert.pem +++ b/test/cert.pem @@ -1,21 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDhzCCAm+gAwIBAgIJAIaYyv22YuvwMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmZvb2Jhci5jb20wHhcNMTYwNTMwMjI1 -ODQ3WhcNMjYwNTI4MjI1ODQ3WjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29t -ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD -VQQDDApmb29iYXIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA -w/aAXD0NgsuGHN9q4XfnPwrbKkdDupaLA+s24QCVDe2qpV9gtiiPeKI3shMbuB45 -QbH/o1jy7uzWkrvWupIP2+geYe9nBKGTHzlQXNuOTggJwpcUah+/HIcCGfLFTw/O -EOjt17LceVFUyfE1rQjRzEQsH7VWzJzUXxZ9ty2fbJuwLG8fyO8dUBs+Mu6ZReWh -L30IxEQx+mhyeuWVciCFe4MePUpxZlKJZq9XOXc+llR8oOABSNifbS3YVQT6CZuw -5d3HvTG+GLF0zjyRn2uB2km6c3lFWt0uqv0cqsabFY5LnNFTGxTi2wWllIalIzgv -PkQitLY3vpjt8xh4VmDX2wIDAQABo1AwTjAdBgNVHQ4EFgQUU8mpMtWlwZRC0g9M -e/zfXEeUnCAwHwYDVR0jBBgwFoAUU8mpMtWlwZRC0g9Me/zfXEeUnCAwDAYDVR0T -BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAT82mdTYTsY/7JILnBkYYUr0VmbD9 -w85IsEBFbY0rTQ2bl38taTG/jQ/5Ivpz8H+7j2dWPO1hTQXTRpI4LmD3AXqzPfz/ -Q4ntNE2emuwLMJN2kIdNhu8RY8lEgsmfObJWOtDiCj5NaNCo7jkEemZALrjDOHmI -lNyoGNOp4epicoZpQ9/6cgjTo4hlaIjZnSUC4VV8BfOPQMBpmqiVhkNHitB8ge7L -BuacFUAk/SoXeWwqjtD4RkQe3zMWk7s441CjOH3fd2JXWRso/np3Ksn5mY2/O1Ct -tlX3qtzYUZlY7cfeHLxvyUkjn8I34RemypUWwdO5BT8MIysBXb5R4GH1+w== +MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub +3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ +mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 +TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI +ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y +euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM +6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE +wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY +oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 +dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp +HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== -----END CERTIFICATE----- diff --git a/test/key.key b/test/key.key new file mode 100644 index 0000000..6b6209f Binary files /dev/null and b/test/key.key differ diff --git a/test/key.pem b/test/key.pem new file mode 100644 index 0000000..d381795 --- /dev/null +++ b/test/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo9CWMRLMXo1CF +/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 +kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS +wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM +jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT +Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt +OzboKgs1AgMBAAECggEBAKLj6IOJBKXolczpzb8UkyAjAkGBektcseV07gelJ/fk +3z0LuWPv5p12E/HlXB24vU2x/ikUbbP3eMsawRzDEahQqmNmPEkYAYUAy/Qpi9GN +DYvn3LqDec4jVgeQKS+p9H2DzUpTogp8zR2//yzbuWBg2+F//xh7vU0S0RQCziPM +x7RSBgbhxSfChfEJbS2sDnzfh0jRQmoY95iFv7puet1FJtzdZ4fgCd1RqmC2lFM5 +H0eZtN/Cz19lieVs0b996DErdEBqClVZO00eYbRozCDaBzRU3ybB/dMrGJxhkkXm +wb3kWMtziH9qOYsostuHIFu8eKFLloKxFnq2R4DGxOECgYEA2KUIZISOeGJSBcLJ +JAUK2gvgXPNo4HHWIwOA9xeN3ZJlsnPlffXQNnm6t1st1V2gfMm9I2n0m/F0y2B/ +n/XGSa8bghfPA9l0c2h58lkL3JQJR/paa8ycTz+YZPrznEyN7Qa0RrJXUvZv9lQL +Hc3+FHcSHgMqDV2f2bHAEu9YGi0CgYEAx6VEIPNvrHFgjo/jk1RTuk+m0xEWQsZL +Cs+izQMr2TaeJn8LG+93AvFuYn0J0nT3WuStLPrUg8i4IhSS6lf1tId5ivIZPm4r +YwMyblBJXhnHbk7Uqodjfw/3s6V2HAu++B7hTdyVr9DFuST9uv4m8bkPV8rfX1jE +I2rAPVWvgikCgYB+wNAQP547wQrMZBLbCDg5KwmyWJfb+b6X7czexOEz6humNTjo +YZHYzY/5B1fhpk3ntQD8X1nGg5caBvOk21+QbOtjShrM3cXMYCw5JvBRtitX+Zo9 +yBEMLOE0877ki8XeEDYZxu5gk98d+D4oygUGZEQtWxyXhVepPt5qNa8OYQKBgQDH +RVgZI6KFlqzv3wMh3PutbS9wYQ+9GrtwUQuIYe/0YSW9+vSVr5E0qNKrD28sV39F +hBauXLady0yvB6YUrjMbPFW+sCMuQzyfGWPO4+g3OrfqjFiM1ZIkE0YEU9Tt7XNx +qTDtTI1D7bhNMnTnniI1B6ge0und+3XafAThs5L48QKBgQCTTpfqMt8kU3tcI9sf +0MK03y7kA76d5uw0pZbWFy7KI4qnzWutCzb+FMPWWsoFtLJLPZy//u/ZCUVFVa4d +0Y/ASNQIESVPXFLAltlLo4MSmsg1vCBsbviEEaPeEjvMrgki93pYtd/aOSgkYC1T +mEq154s5rmqh+h+XRIf7Au0SLw== +-----END PRIVATE KEY-----