Skip to content

Commit

Permalink
Added support for silent flag
Browse files Browse the repository at this point in the history
  • Loading branch information
ancwrd1 committed Dec 13, 2024
1 parent c377b43 commit 0ae70b2
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rustls-cng"
version = "0.5.3"
version = "0.6.0"
authors = ["Dmitry Pankratov <dmitry@pankratov.net>"]
description = "Windows CNG API bridge for rustls"
license = "MIT/Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn get_chain(
let context = contexts
.first()
.ok_or_else(|| anyhow::Error::msg("No client cert"))?;
let key = context.acquire_key()?;
let key = context.acquire_key(true)?;
let signing_key = CngSigningKey::new(key)?;
let chain = context
.as_chain_der()?
Expand Down
2 changes: 1 addition & 1 deletion examples/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl ResolvesServerCert for ServerCertResolver {

// attempt to acquire a private key and construct CngSigningKey
let (context, key) = contexts.into_iter().find_map(|ctx| {
let key = ctx.acquire_key().ok()?;
let key = ctx.acquire_key(true).ok()?;
if let Some(ref pin) = self.pin {
key.set_pin(pin).ok()?;
}
Expand Down
18 changes: 13 additions & 5 deletions src/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,15 @@ impl CertContext {
unsafe { &*self.0.inner() }
}

/// Attempt to silently acquire a CNG private key from this context.
pub fn acquire_key(&self) -> Result<NCryptKey> {
/// Attempt to acquire a CNG private key from this context.
/// The `silent` parameter indicates whether to suppress the user prompts.
pub fn acquire_key(&self, silent: bool) -> Result<NCryptKey> {
let mut handle = HCRYPTPROV_OR_NCRYPT_KEY_HANDLE::default();
let mut key_spec = CERT_KEY_SPEC::default();
let flags = CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG | CRYPT_ACQUIRE_SILENT_FLAG;

let flags =
if silent { CRYPT_ACQUIRE_SILENT_FLAG } else { 0 } | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;

unsafe {
let result = CryptAcquireCertificatePrivateKey(
self.inner(),
Expand All @@ -72,7 +76,9 @@ impl CertContext {
ptr::null_mut(),
) != 0;
if result {
Ok(NCryptKey::new_owned(handle))
let mut key = NCryptKey::new_owned(handle);
key.set_silent(silent);
Ok(key)
} else {
Err(CngError::from_win32_error())
}
Expand Down Expand Up @@ -137,7 +143,9 @@ impl CertContext {

for (index, element) in elements.iter().enumerate() {
if index != 0 {
if 0 != ((**element).TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
if 0 != ((**element).TrustStatus.dwInfoStatus
& CERT_TRUST_IS_SELF_SIGNED)
{
break;
}
}
Expand Down
27 changes: 21 additions & 6 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,31 @@ impl Drop for InnerKey {

/// CNG private key wrapper
#[derive(Clone, Debug)]
pub struct NCryptKey(Arc<InnerKey>);
pub struct NCryptKey {
inner: Arc<InnerKey>,
silent: bool,
}

impl NCryptKey {
/// Create an owned instance which frees the underlying handle automatically
pub fn new_owned(handle: NCRYPT_KEY_HANDLE) -> Self {
NCryptKey(Arc::new(InnerKey::Owned(handle)))
NCryptKey {
inner: Arc::new(InnerKey::Owned(handle)),
silent: true,
}
}

/// Create a borrowed instance which doesn't free the key handle
pub fn new_borrowed(handle: NCRYPT_KEY_HANDLE) -> Self {
NCryptKey(Arc::new(InnerKey::Borrowed(handle)))
NCryptKey {
inner: Arc::new(InnerKey::Borrowed(handle)),
silent: true,
}
}

/// Return an inner CNG key handle
pub fn inner(&self) -> NCRYPT_KEY_HANDLE {
self.0.inner()
self.inner.inner()
}

fn get_string_property(&self, property: PCWSTR) -> Result<String> {
Expand Down Expand Up @@ -160,6 +169,11 @@ impl NCryptKey {
CngError::from_hresult(result)
}

/// Enable or disable silent key operations without prompting the user. The default value is 'true'.
pub fn set_silent(&mut self, silent: bool) {
self.silent = silent;
}

/// Sign a given digest with this key. The `hash` slice must be 32, 48 or 64 bytes long.
pub fn sign(&self, hash: &[u8], padding: SignaturePadding) -> Result<Vec<u8>> {
unsafe {
Expand Down Expand Up @@ -189,6 +203,7 @@ impl NCryptKey {
};

let mut result = 0;
let dwflags = flag | if self.silent { NCRYPT_SILENT_FLAG } else { 0 };

CngError::from_hresult(NCryptSignHash(
self.inner(),
Expand All @@ -198,7 +213,7 @@ impl NCryptKey {
ptr::null_mut(),
0,
&mut result,
NCRYPT_SILENT_FLAG | flag,
dwflags,
))?;

let mut signature = vec![0u8; result as usize];
Expand All @@ -211,7 +226,7 @@ impl NCryptKey {
signature.as_mut_ptr(),
signature.len() as u32,
&mut result,
NCRYPT_SILENT_FLAG | flag,
dwflags,
))?;

Ok(signature)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_client_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ mod client {
let context = contexts
.first()
.ok_or_else(|| anyhow::Error::msg("No client cert"))?;
let key = context.acquire_key()?;
let key = context.acquire_key(true)?;
let signing_key = CngSigningKey::new(key)?;
let chain = context
.as_chain_der()?
Expand Down Expand Up @@ -123,7 +123,7 @@ mod server {
let contexts = self.0.find_by_subject_str(name).ok()?;

let (context, key) = contexts.into_iter().find_map(|ctx| {
let key = ctx.acquire_key().ok()?;
let key = ctx.acquire_key(true).ok()?;
CngSigningKey::new(key).ok().map(|key| (ctx, key))
})?;

Expand Down
2 changes: 1 addition & 1 deletion tests/test_sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn test_sign() {
SignatureScheme::ECDSA_NISTP384_SHA384,
];

let key = context.acquire_key().unwrap();
let key = context.acquire_key(true).unwrap();
let signing_key = CngSigningKey::new(key).unwrap();
assert_eq!(signing_key.algorithm(), SignatureAlgorithm::ECDSA);
let signer = signing_key.choose_scheme(&offered).unwrap();
Expand Down

0 comments on commit 0ae70b2

Please sign in to comment.