diff --git a/Cargo.toml b/Cargo.toml index bbde234..906f128 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,8 @@ default-target = "x86_64-pc-windows-msvc" [dependencies] lazy_static = "1.0" -winapi = { version = "0.3", features = ["lmcons", "minschannel", "securitybaseapi", "schannel", "sspi", "sysinfoapi", "timezoneapi", "winbase", "wincrypt", "winerror"] } +winapi = { version = "0.3", features = ["minwindef", "ntdef", "lmcons", "minschannel", "securitybaseapi", "schannel", "sspi", "sysinfoapi", "timezoneapi", "winbase", "wincrypt", "winerror", "ncrypt"] } + + +[features] +allow-deprecated = [] diff --git a/src/cert_context.rs b/src/cert_context.rs index 8ec3a85..7aabc28 100644 --- a/src/cert_context.rs +++ b/src/cert_context.rs @@ -13,7 +13,8 @@ use winapi::um::wincrypt; use crate::Inner; use crate::ncrypt_key::NcryptKey; -use crate::crypt_prov::{CryptProv, ProviderType}; +#[cfg(feature = "allow-deprecated")] +use crate::deprecated::crypt_prov::{CryptProv, ProviderType}; use crate::cert_store::CertStore; /// A supported hashing algorithm @@ -456,7 +457,13 @@ impl<'a> AcquirePrivateKeyOptions<'a> { /// Acquires the private key handle. pub fn acquire(&self) -> io::Result { unsafe { - let flags = self.flags | wincrypt::CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG; + let api_flag = if cfg!(feature = "allow-deprecated") { + wincrypt::CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG + } else { + wincrypt:: CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG + }; + + let flags = self.flags | api_flag; let mut handle = 0; let mut spec = 0; let mut free = winapi::FALSE; @@ -471,10 +478,15 @@ impl<'a> AcquirePrivateKeyOptions<'a> { } assert!(free == winapi::TRUE); if spec & wincrypt::CERT_NCRYPT_KEY_SPEC != 0 { - Ok(PrivateKey::NcryptKey(NcryptKey::from_inner(handle))) - } else { - Ok(PrivateKey::CryptProv(CryptProv::from_inner(handle))) - } + return Ok(PrivateKey::NcryptKey(NcryptKey::from_inner(handle))); + } + + #[cfg(feature = "allow-deprecated")] + return Ok(PrivateKey::CryptProv(CryptProv::from_inner(handle))); + + #[cfg(not(feature = "allow-deprecated"))] + return Err(io::Error::new(io::ErrorKind::Other, "Api failure")); + } } } @@ -482,6 +494,7 @@ impl<'a> AcquirePrivateKeyOptions<'a> { /// The private key associated with a certificate context. pub enum PrivateKey { /// A CryptoAPI provider. + #[cfg(feature = "allow-deprecated")] CryptProv(CryptProv), /// A CNG provider. NcryptKey(NcryptKey), @@ -520,6 +533,7 @@ impl<'a> SetKeyProvInfo<'a> { /// /// If not provided, the key container is one of the CNG key storage /// providers. + #[cfg(feature = "allow-deprecated")] pub fn type_(&mut self, type_: ProviderType) -> &mut SetKeyProvInfo<'a> { self.type_ = type_.as_raw(); self diff --git a/src/crypt_key.rs b/src/deprecated/crypt_key.rs similarity index 100% rename from src/crypt_key.rs rename to src/deprecated/crypt_key.rs diff --git a/src/crypt_prov.rs b/src/deprecated/crypt_prov.rs similarity index 65% rename from src/crypt_prov.rs rename to src/deprecated/crypt_prov.rs index 3eabb86..80f6648 100644 --- a/src/crypt_prov.rs +++ b/src/deprecated/crypt_prov.rs @@ -6,9 +6,8 @@ use winapi::shared::minwindef as winapi; use winapi::shared::ntdef; use winapi::um::winbase; use winapi::um::wincrypt; - +use crate::deprecated::crypt_key::CryptKey; use crate::Inner; -use crate::crypt_key::CryptKey; /// A CryptoAPI handle to a provider of a key. pub struct CryptProv(wincrypt::HCRYPTPROV); @@ -98,15 +97,25 @@ impl AcquireOptions { /// 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 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 = wincrypt::CryptAcquireContextW(&mut prov, - container as *mut _, - provider as *mut _, - type_.0, - self.flags); + let res = wincrypt::CryptAcquireContextW( + &mut prov, + container as *mut _, + provider as *mut _, + type_.0, + self.flags, + ); if res == winapi::TRUE { Ok(CryptProv(prov)) } else { @@ -181,15 +190,16 @@ impl<'a> ImportOptions<'a> { assert!(der.len() <= winapi::DWORD::max_value() as usize); let mut buf = ptr::null_mut(); let mut len = 0; - let res = wincrypt::CryptDecodeObjectEx(wincrypt::X509_ASN_ENCODING | - wincrypt::PKCS_7_ASN_ENCODING, - wincrypt::PKCS_RSA_PRIVATE_KEY, - der.as_ptr(), - der.len() as winapi::DWORD, - wincrypt::CRYPT_DECODE_ALLOC_FLAG, - ptr::null_mut(), - &mut buf as *mut _ as winapi::LPVOID, - &mut len); + let res = wincrypt::CryptDecodeObjectEx( + wincrypt::X509_ASN_ENCODING | wincrypt::PKCS_7_ASN_ENCODING, + wincrypt::PKCS_RSA_PRIVATE_KEY, + der.as_ptr(), + der.len() as winapi::DWORD, + wincrypt::CRYPT_DECODE_ALLOC_FLAG, + ptr::null_mut(), + &mut buf as *mut _ as winapi::LPVOID, + &mut len, + ); if res == winapi::FALSE { return Err(io::Error::last_os_error()); } @@ -214,15 +224,16 @@ impl<'a> ImportOptions<'a> { // Decode the der format into a CRYPT_PRIVATE_KEY_INFO struct let mut buf = ptr::null_mut(); let mut len = 0; - let res = wincrypt::CryptDecodeObjectEx(wincrypt::X509_ASN_ENCODING | - wincrypt::PKCS_7_ASN_ENCODING, - wincrypt::PKCS_PRIVATE_KEY_INFO, - der.as_ptr(), - der.len() as winapi::DWORD, - wincrypt::CRYPT_DECODE_ALLOC_FLAG, - ptr::null_mut(), - &mut buf as *mut _ as winapi::LPVOID, - &mut len); + let res = wincrypt::CryptDecodeObjectEx( + wincrypt::X509_ASN_ENCODING | wincrypt::PKCS_7_ASN_ENCODING, + wincrypt::PKCS_PRIVATE_KEY_INFO, + der.as_ptr(), + der.len() as winapi::DWORD, + wincrypt::CRYPT_DECODE_ALLOC_FLAG, + ptr::null_mut(), + &mut buf as *mut _ as winapi::LPVOID, + &mut len, + ); if res == winapi::FALSE { return Err(io::Error::last_os_error()); } @@ -245,11 +256,14 @@ impl<'a> ImportOptions<'a> { .trim(); if pem_str.starts_with("-----") { - if !pem_str.starts_with("-----BEGIN PRIVATE KEY-----") || - !pem_str.ends_with("-----END PRIVATE KEY-----") { - return Err(io::Error::new(io::ErrorKind::InvalidData, - "expected '-----BEGIN PRIVATE KEY-----'\ - and '-----END PRIVATE KEY-----' PEM guards")); + if !pem_str.starts_with("-----BEGIN PRIVATE KEY-----") + || !pem_str.ends_with("-----END PRIVATE KEY-----") + { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "expected '-----BEGIN PRIVATE KEY-----'\ + and '-----END PRIVATE KEY-----' PEM guards", + )); } } unsafe { @@ -258,26 +272,30 @@ impl<'a> ImportOptions<'a> { // Decode the pem wrapper before passing it to import_pkcs8 // Call once first to figure out the necessary buffer size let mut len = 0; - let res = wincrypt::CryptStringToBinaryA(pem.as_ptr() as ntdef::LPCSTR, - pem.len() as winapi::DWORD, - wincrypt::CRYPT_STRING_BASE64_ANY, - ptr::null_mut(), - &mut len, - ptr::null_mut(), - ptr::null_mut()); + let res = wincrypt::CryptStringToBinaryA( + pem.as_ptr() as ntdef::LPCSTR, + pem.len() as winapi::DWORD, + wincrypt::CRYPT_STRING_BASE64_ANY, + ptr::null_mut(), + &mut len, + ptr::null_mut(), + ptr::null_mut(), + ); if res == winapi::FALSE { return Err(io::Error::last_os_error()); } // Call second time to actually get the DER bytes let mut der_buf = vec![0; len as usize]; - let res = wincrypt::CryptStringToBinaryA(pem.as_ptr() as ntdef::LPCSTR, - pem.len() as winapi::DWORD, - wincrypt::CRYPT_STRING_BASE64_ANY, - der_buf.as_mut_ptr(), - &mut len, - ptr::null_mut(), - ptr::null_mut()); + let res = wincrypt::CryptStringToBinaryA( + pem.as_ptr() as ntdef::LPCSTR, + pem.len() as winapi::DWORD, + wincrypt::CRYPT_STRING_BASE64_ANY, + der_buf.as_mut_ptr(), + &mut len, + ptr::null_mut(), + ptr::null_mut(), + ); if res == winapi::FALSE { return Err(io::Error::last_os_error()); } @@ -299,9 +317,7 @@ mod test { .verify_context(true) .acquire(ProviderType::rsa_full()) .unwrap(); - context.import() - .import(key) - .unwrap(); + context.import().import(key).unwrap(); } #[test] @@ -309,30 +325,36 @@ mod test { let key = include_str!("../test/key.pem"); let der = unsafe { let mut len = 0; - assert!(wincrypt::CryptStringToBinaryA(key.as_ptr() as ntdef::LPCSTR, - key.len() as winapi::DWORD, - wincrypt::CRYPT_STRING_BASE64HEADER, - ptr::null_mut(), - &mut len, - ptr::null_mut(), - ptr::null_mut()) == winapi::TRUE); + assert!( + wincrypt::CryptStringToBinaryA( + key.as_ptr() as ntdef::LPCSTR, + key.len() as winapi::DWORD, + wincrypt::CRYPT_STRING_BASE64HEADER, + ptr::null_mut(), + &mut len, + ptr::null_mut(), + ptr::null_mut() + ) == winapi::TRUE + ); let mut buf = vec![0; len as usize]; - assert!(wincrypt::CryptStringToBinaryA(key.as_ptr() as ntdef::LPCSTR, - key.len() as winapi::DWORD, - wincrypt::CRYPT_STRING_BASE64HEADER, - buf.as_mut_ptr(), - &mut len, - ptr::null_mut(), - ptr::null_mut()) == winapi::TRUE); + assert!( + wincrypt::CryptStringToBinaryA( + key.as_ptr() as ntdef::LPCSTR, + key.len() as winapi::DWORD, + wincrypt::CRYPT_STRING_BASE64HEADER, + buf.as_mut_ptr(), + &mut len, + ptr::null_mut(), + ptr::null_mut() + ) == winapi::TRUE + ); buf }; let mut context = AcquireOptions::new() .verify_context(true) .acquire(ProviderType::rsa_full()) .unwrap(); - context.import() - .import_pkcs8(&der) - .unwrap(); + context.import().import_pkcs8(&der).unwrap(); } #[test] @@ -343,9 +365,7 @@ mod test { .verify_context(true) .acquire(ProviderType::rsa_full()) .unwrap(); - assert!(context.import() - .import_pkcs8(&key[..]) - .is_err()); + assert!(context.import().import_pkcs8(&key[..]).is_err()); } #[test] @@ -355,9 +375,7 @@ mod test { .verify_context(true) .acquire(ProviderType::rsa_full()) .unwrap(); - context.import() - .import_pkcs8_pem(key) - .unwrap(); + context.import().import_pkcs8_pem(key).unwrap(); } #[test] @@ -367,9 +385,7 @@ mod test { .verify_context(true) .acquire(ProviderType::rsa_full()) .unwrap(); - context.import() - .import_pkcs8_pem(key) - .unwrap(); + context.import().import_pkcs8_pem(key).unwrap(); } #[test] @@ -379,9 +395,7 @@ mod test { .verify_context(true) .acquire(ProviderType::rsa_full()) .unwrap(); - assert!(context.import() - .import_pkcs8_pem(key) - .is_err()); + assert!(context.import().import_pkcs8_pem(key).is_err()); } #[test] @@ -391,9 +405,7 @@ mod test { .verify_context(true) .acquire(ProviderType::rsa_full()) .unwrap(); - assert!(context.import() - .import_pkcs8_pem(key) - .is_err()); + assert!(context.import().import_pkcs8_pem(key).is_err()); } #[test] @@ -403,8 +415,6 @@ mod test { .verify_context(true) .acquire(ProviderType::rsa_full()) .unwrap(); - assert!(context.import() - .import_pkcs8_pem(key) - .is_err()); + assert!(context.import().import_pkcs8_pem(key).is_err()); } } diff --git a/src/deprecated/mod.rs b/src/deprecated/mod.rs new file mode 100644 index 0000000..32240ba --- /dev/null +++ b/src/deprecated/mod.rs @@ -0,0 +1,2 @@ +pub mod crypt_key; +pub mod crypt_prov; diff --git a/src/lib.rs b/src/lib.rs index 81d63f1..24c4401 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,12 +37,12 @@ macro_rules! inner { self.0 as *mut _ } } - } + }; } /// Allows access to the underlying schannel API representation of a wrapped data type -/// -/// Performing actions with internal handles might lead to the violation of internal assumptions +/// +/// Performing actions with internal handles might lead to the violation of internal assumptions /// and therefore is inherently unsafe. pub trait RawPointer { /// Constructs an instance of this type from its handle / pointer. @@ -55,9 +55,14 @@ pub trait RawPointer { pub mod cert_chain; pub mod cert_context; pub mod cert_store; -pub mod crypt_key; -pub mod crypt_prov; -/* pub */ mod ctl_context; + +#[cfg(feature = "allow-deprecated")] +mod deprecated; +#[cfg(feature = "allow-deprecated")] +pub use deprecated::*; + +/* pub */ +mod ctl_context; pub mod key_handle; pub mod ncrypt_key; pub mod schannel_cred; @@ -70,15 +75,20 @@ mod security_context; #[cfg(test)] mod test; -const ACCEPT_REQUESTS: ctypes::c_ulong = - sspi::ASC_REQ_ALLOCATE_MEMORY | sspi::ASC_REQ_CONFIDENTIALITY | - sspi::ASC_REQ_SEQUENCE_DETECT | sspi::ASC_REQ_STREAM | - sspi::ASC_REQ_REPLAY_DETECT; - -const INIT_REQUESTS: ctypes::c_ulong = - sspi::ISC_REQ_CONFIDENTIALITY | sspi::ISC_REQ_INTEGRITY | sspi::ISC_REQ_REPLAY_DETECT | - sspi::ISC_REQ_SEQUENCE_DETECT | sspi::ISC_REQ_MANUAL_CRED_VALIDATION | - sspi::ISC_REQ_ALLOCATE_MEMORY | sspi::ISC_REQ_STREAM | sspi::ISC_REQ_USE_SUPPLIED_CREDS; +const ACCEPT_REQUESTS: ctypes::c_ulong = sspi::ASC_REQ_ALLOCATE_MEMORY + | sspi::ASC_REQ_CONFIDENTIALITY + | sspi::ASC_REQ_SEQUENCE_DETECT + | sspi::ASC_REQ_STREAM + | sspi::ASC_REQ_REPLAY_DETECT; + +const INIT_REQUESTS: ctypes::c_ulong = sspi::ISC_REQ_CONFIDENTIALITY + | sspi::ISC_REQ_INTEGRITY + | sspi::ISC_REQ_REPLAY_DETECT + | sspi::ISC_REQ_SEQUENCE_DETECT + | sspi::ISC_REQ_MANUAL_CRED_VALIDATION + | sspi::ISC_REQ_ALLOCATE_MEMORY + | sspi::ISC_REQ_STREAM + | sspi::ISC_REQ_USE_SUPPLIED_CREDS; trait Inner { unsafe fn from_inner(t: T) -> Self; @@ -88,8 +98,7 @@ trait Inner { fn get_mut(&mut self) -> &mut T; } -unsafe fn secbuf(buftype: ctypes::c_ulong, - bytes: Option<&mut [u8]>) -> sspi::SecBuffer { +unsafe fn secbuf(buftype: ctypes::c_ulong, bytes: Option<&mut [u8]>) -> sspi::SecBuffer { let (ptr, len) = match bytes { Some(bytes) => (bytes.as_mut_ptr(), bytes.len() as ctypes::c_ulong), None => (ptr::null_mut(), 0), diff --git a/src/test.rs b/src/test.rs index 4534893..7c19ec4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -11,6 +11,7 @@ use winapi::um::{minwinbase, sysinfoapi, timezoneapi, wincrypt}; use crate::Inner; use crate::alpn_list::AlpnList; +#[cfg(feature = "allow-deprecated")] use crate::crypt_prov::{AcquireOptions, ProviderType}; use crate::cert_context::{CertContext, KeySpec, HashAlgorithm}; use crate::cert_store::{CertStore, Memory, CertAdd}; @@ -658,6 +659,7 @@ fn accept_one_byte_at_a_time() { } #[test] +#[cfg(feature = "allow-deprecated")] fn split_cert_key() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap();