Skip to content

Commit c54087a

Browse files
MS-megliuancwrd1
authored andcommitted
added local machine and no-root supprot for as_chain_der()
1 parent 130765e commit c54087a

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

examples/client.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustls::{
1313
use rustls_pki_types::{CertificateDer, ServerName};
1414

1515
use rustls_cng::{
16+
cert::ChainEngineType,
1617
signer::CngSigningKey,
1718
store::{CertStore, CertStoreType},
1819
};
@@ -37,7 +38,7 @@ fn get_chain(
3738
let key = context.acquire_key()?;
3839
let signing_key = CngSigningKey::new(key)?;
3940
let chain = context
40-
.as_chain_der()?
41+
.as_chain_der(true, ChainEngineType::HkeyLocalMachine)?
4142
.into_iter()
4243
.map(Into::into)
4344
.collect();

examples/server.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustls::{
1313
};
1414

1515
use rustls_cng::{
16+
cert::ChainEngineType,
1617
signer::CngSigningKey,
1718
store::{CertStore, CertStoreType},
1819
};
@@ -74,7 +75,9 @@ impl ResolvesServerCert for ServerCertResolver {
7475
println!("Key alg: {:?}", key.key().algorithm());
7576

7677
// attempt to acquire a full certificate chain
77-
let chain = context.as_chain_der().ok()?;
78+
let chain = context
79+
.as_chain_der(true, ChainEngineType::HkeyLocalMachine)
80+
.ok()?;
7881
let certs = chain.into_iter().map(Into::into).collect();
7982

8083
// return CertifiedKey instance

src/cert.rs

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@ use windows_sys::Win32::Security::Cryptography::*;
66

77
use crate::{error::CngError, key::NCryptKey, Result};
88

9+
const HCCE_LOCAL_MACHINE: HCERTCHAINENGINE = 0x1 as HCERTCHAINENGINE;
10+
911
#[derive(Debug)]
1012
enum InnerContext {
1113
Owned(*const CERT_CONTEXT),
1214
Borrowed(*const CERT_CONTEXT),
1315
}
1416

17+
pub enum ChainEngineType {
18+
HkeyCurrentUser,
19+
HkeyLocalMachine,
20+
}
21+
1522
unsafe impl Send for InnerContext {}
1623
unsafe impl Sync for InnerContext {}
1724

@@ -86,9 +93,59 @@ impl CertContext {
8693
)
8794
}
8895
}
96+
/*
97+
/// Return DER-encoded X.509 certificate chain
98+
pub fn as_chain_der(&self) -> Result<Vec<Vec<u8>>> {
99+
unsafe {
100+
let param = CERT_CHAIN_PARA {
101+
cbSize: mem::size_of::<CERT_CHAIN_PARA>() as u32,
102+
RequestedUsage: std::mem::zeroed(),
103+
};
104+
105+
let mut context: *mut CERT_CHAIN_CONTEXT = ptr::null_mut();
106+
107+
let result = CertGetCertificateChain(
108+
HCERTCHAINENGINE::default(),
109+
self.inner(),
110+
ptr::null(),
111+
ptr::null_mut(),
112+
&param,
113+
0,
114+
ptr::null(),
115+
&mut context,
116+
) != 0;
117+
118+
if result {
119+
let mut chain = vec![];
120+
121+
if (*context).cChain > 0 {
122+
let chain_ptr = *(*context).rgpChain;
123+
let elements = slice::from_raw_parts(
124+
(*chain_ptr).rgpElement,
125+
(*chain_ptr).cElement as usize,
126+
);
127+
for element in elements {
128+
let context = (**element).pCertContext;
129+
chain.push(Self::new_borrowed(context).as_der().to_vec());
130+
}
131+
}
132+
133+
CertFreeCertificateChain(&*context);
89134
90-
/// Return DER-encoded X.509 certificate chain
91-
pub fn as_chain_der(&self) -> Result<Vec<Vec<u8>>> {
135+
Ok(chain)
136+
} else {
137+
Err(CngError::from_win32_error())
138+
}
139+
}
140+
}
141+
*/
142+
/// Return DER-encoded X.509 certificate chain.
143+
/// Giving user options to (1) not to include the root. (2) to use the HKLM engine instead of default HKCU engine
144+
pub fn as_chain_der(
145+
&self,
146+
include_root: bool,
147+
chain_engine: ChainEngineType,
148+
) -> Result<Vec<Vec<u8>>> {
92149
unsafe {
93150
let param = CERT_CHAIN_PARA {
94151
cbSize: mem::size_of::<CERT_CHAIN_PARA>() as u32,
@@ -97,8 +154,13 @@ impl CertContext {
97154

98155
let mut context: *mut CERT_CHAIN_CONTEXT = ptr::null_mut();
99156

157+
let chain_engine = match chain_engine {
158+
ChainEngineType::HkeyLocalMachine => HCCE_LOCAL_MACHINE as isize,
159+
ChainEngineType::HkeyCurrentUser => HCERTCHAINENGINE::default() as isize,
160+
};
161+
100162
let result = CertGetCertificateChain(
101-
HCERTCHAINENGINE::default(),
163+
chain_engine,
102164
self.inner(),
103165
ptr::null(),
104166
ptr::null_mut(),
@@ -117,7 +179,19 @@ impl CertContext {
117179
(*chain_ptr).rgpElement,
118180
(*chain_ptr).cElement as usize,
119181
);
182+
183+
let mut first = true;
120184
for element in elements {
185+
if first {
186+
first = false;
187+
} else if !include_root {
188+
if 0 != ((**element).TrustStatus.dwInfoStatus
189+
& CERT_TRUST_IS_SELF_SIGNED)
190+
{
191+
break;
192+
}
193+
}
194+
121195
let context = (**element).pCertContext;
122196
chain.push(Self::new_borrowed(context).as_der().to_vec());
123197
}

tests/test_client_server.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ mod client {
1616
};
1717
use rustls_pki_types::CertificateDer;
1818

19-
use rustls_cng::{signer::CngSigningKey, store::CertStore};
19+
use rustls_cng::{cert::ChainEngineType, signer::CngSigningKey, store::CertStore};
2020

2121
#[derive(Debug)]
2222
pub struct ClientCertResolver(CertStore, String);
@@ -32,7 +32,7 @@ mod client {
3232
let key = context.acquire_key()?;
3333
let signing_key = CngSigningKey::new(key)?;
3434
let chain = context
35-
.as_chain_der()?
35+
.as_chain_der(true, ChainEngineType::HkeyLocalMachine)?
3636
.into_iter()
3737
.map(Into::into)
3838
.collect();
@@ -111,7 +111,7 @@ mod server {
111111
RootCertStore, ServerConfig, ServerConnection, Stream,
112112
};
113113

114-
use rustls_cng::{signer::CngSigningKey, store::CertStore};
114+
use rustls_cng::{cert::ChainEngineType, signer::CngSigningKey, store::CertStore};
115115

116116
#[derive(Debug)]
117117
pub struct ServerCertResolver(CertStore);
@@ -127,7 +127,9 @@ mod server {
127127
CngSigningKey::new(key).ok().map(|key| (ctx, key))
128128
})?;
129129

130-
let chain = context.as_chain_der().ok()?;
130+
let chain = context
131+
.as_chain_der(true, ChainEngineType::HkeyLocalMachine)
132+
.ok()?;
131133
let certs = chain.into_iter().map(Into::into).collect();
132134

133135
Some(Arc::new(CertifiedKey {

0 commit comments

Comments
 (0)