Skip to content

Commit 40872c6

Browse files
committed
Added Pkcs12Flags to control how to import chains from the PKCS#12
1 parent 655d99a commit 40872c6

File tree

8 files changed

+87
-40
lines changed

8 files changed

+87
-40
lines changed

Cargo.lock

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ no-default-features = true
1919
rustls = { git = "https://github.com/rustls/rustls.git", default-features = false, features = ["std"] }
2020
rustls-pki-types = "1"
2121
time = { version = "0.3.43", default-features = false, optional = true }
22+
bitflags = "2"
2223
windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Security_Cryptography"] }
2324

2425
[dev-dependencies]

examples/client.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
use std::{
2+
hash::Hasher,
3+
io::{Read, Write},
4+
net::{Shutdown, TcpStream},
5+
path::PathBuf,
6+
sync::Arc,
7+
};
8+
19
use clap::Parser;
210
use rustls::{
311
ClientConfig, ClientConnection, RootCertStore, Stream,
@@ -6,17 +14,10 @@ use rustls::{
614
enums::CertificateType,
715
};
816
use rustls_pki_types::{CertificateDer, ServerName};
9-
use std::hash::Hasher;
10-
use std::{
11-
io::{Read, Write},
12-
net::{Shutdown, TcpStream},
13-
path::PathBuf,
14-
sync::Arc,
15-
};
1617

1718
use rustls_cng::{
1819
signer::CngSigningKey,
19-
store::{CertStore, CertStoreType},
20+
store::{CertStore, CertStoreType, Pkcs12Flags},
2021
};
2122

2223
const PORT: u16 = 8000;
@@ -110,7 +111,11 @@ fn main() -> anyhow::Result<()> {
110111

111112
let store = if let Some(ref keystore) = params.keystore {
112113
let data = std::fs::read(keystore)?;
113-
CertStore::from_pkcs12(&data, params.password.as_deref().unwrap_or_default())?
114+
CertStore::from_pkcs12(
115+
&data,
116+
params.password.as_deref().unwrap_or_default(),
117+
Pkcs12Flags::default(),
118+
)?
114119
} else {
115120
CertStore::open(CertStoreType::CurrentUser, "my")?
116121
};

examples/server.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustls::{
1111
crypto::{Credentials, Identity, SelectedCredential, aws_lc_rs},
1212
server::{ClientHello, ServerCredentialResolver, WebPkiClientVerifier},
1313
};
14+
use rustls_cng::store::Pkcs12Flags;
1415
use rustls_cng::{
1516
signer::CngSigningKey,
1617
store::{CertStore, CertStoreType},
@@ -132,7 +133,11 @@ fn main() -> anyhow::Result<()> {
132133

133134
let store = if let Some(ref keystore) = params.keystore {
134135
let data = std::fs::read(keystore)?;
135-
CertStore::from_pkcs12(&data, params.password.as_deref().unwrap_or_default())?
136+
CertStore::from_pkcs12(
137+
&data,
138+
params.password.as_deref().unwrap_or_default(),
139+
Pkcs12Flags::default(),
140+
)?
136141
} else {
137142
CertStore::open(CertStoreType::CurrentUser, "my")?
138143
};

src/store.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Windows certificate store wrapper
22
3+
use bitflags::bitflags;
34
use std::{os::raw::c_void, ptr};
4-
55
use windows_sys::Win32::Security::Cryptography::*;
66

77
use crate::{Result, cert::CertContext, error::CngError};
@@ -22,6 +22,24 @@ pub enum CertStoreType {
2222
CurrentService,
2323
}
2424

25+
bitflags! {
26+
/// Set of flags to pass to the ` CertStore::from_pkcs12 ` method.
27+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
28+
pub struct Pkcs12Flags: u32 {
29+
const INCLUDE_EXTENDED_PROPERTIES = 0x0010;
30+
const PREFER_CNG_KSP = 0x0000_0100;
31+
const ALWAYS_CNG_KSP = 0x0000_0200;
32+
const ALLOW_OVERWRITE_KEY = 0x0000_4000;
33+
const NO_PERSIST_KEY =0x0000_8000;
34+
}
35+
}
36+
37+
impl Default for Pkcs12Flags {
38+
fn default() -> Self {
39+
Pkcs12Flags::INCLUDE_EXTENDED_PROPERTIES | Pkcs12Flags::PREFER_CNG_KSP
40+
}
41+
}
42+
2543
impl CertStoreType {
2644
fn as_flags(&self) -> u32 {
2745
match self {
@@ -71,19 +89,16 @@ impl CertStore {
7189
}
7290

7391
/// Import certificate store from PKCS12 file
74-
pub fn from_pkcs12(data: &[u8], password: &str) -> Result<CertStore> {
92+
pub fn from_pkcs12(data: &[u8], password: &str, flags: Pkcs12Flags) -> Result<CertStore> {
7593
unsafe {
7694
let blob = CRYPT_INTEGER_BLOB {
7795
cbData: data.len() as u32,
7896
pbData: data.as_ptr() as _,
7997
};
8098

8199
let password = utf16z!(password);
82-
let store = PFXImportCertStore(
83-
&blob,
84-
password.as_ptr(),
85-
CRYPT_EXPORTABLE | PKCS12_INCLUDE_EXTENDED_PROPERTIES | PKCS12_PREFER_CNG_KSP,
86-
);
100+
let store =
101+
PFXImportCertStore(&blob, password.as_ptr(), CRYPT_EXPORTABLE | flags.bits());
87102
if store.is_null() {
88103
Err(CngError::from_win32_error())
89104
} else {

tests/test_client_server.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,25 @@ const SERVER_PFX: &[u8] = include_bytes!("assets/rustls-server.pfx");
44
const PASSWORD: &str = "changeit";
55

66
mod client {
7+
use std::{
8+
hash::Hasher,
9+
io::{Read, Write},
10+
net::{Shutdown, TcpStream},
11+
sync::Arc,
12+
};
13+
714
use rustls::{
815
ClientConfig, ClientConnection, RootCertStore, Stream,
916
client::{ClientCredentialResolver, CredentialRequest},
1017
crypto::{Credentials, Identity, SelectedCredential, aws_lc_rs},
1118
enums::CertificateType,
1219
};
1320
use rustls_pki_types::CertificateDer;
14-
use std::hash::Hasher;
15-
use std::{
16-
io::{Read, Write},
17-
net::{Shutdown, TcpStream},
18-
sync::Arc,
19-
};
2021

21-
use rustls_cng::{signer::CngSigningKey, store::CertStore};
22+
use rustls_cng::{
23+
signer::CngSigningKey,
24+
store::{CertStore, Pkcs12Flags},
25+
};
2226

2327
#[derive(Debug)]
2428
pub struct ClientCertResolver(CertStore, String);
@@ -59,7 +63,8 @@ mod client {
5963
}
6064

6165
pub fn run_client(port: u16) -> anyhow::Result<()> {
62-
let store = CertStore::from_pkcs12(super::CLIENT_PFX, super::PASSWORD)?;
66+
let store =
67+
CertStore::from_pkcs12(super::CLIENT_PFX, super::PASSWORD, Pkcs12Flags::default())?;
6368

6469
let ca_cert_context = store.find_by_subject_str(super::CA_SUBJECT)?;
6570
let ca_cert = ca_cert_context.first().unwrap();
@@ -105,7 +110,10 @@ mod server {
105110
crypto::{Credentials, Identity, SelectedCredential, aws_lc_rs},
106111
server::{ClientHello, ServerCredentialResolver, WebPkiClientVerifier},
107112
};
108-
use rustls_cng::{signer::CngSigningKey, store::CertStore};
113+
use rustls_cng::{
114+
signer::CngSigningKey,
115+
store::{CertStore, Pkcs12Flags},
116+
};
109117

110118
#[derive(Debug)]
111119
pub struct ServerCertResolver(CertStore);
@@ -155,7 +163,8 @@ mod server {
155163
}
156164

157165
pub fn run_server(sender: Sender<u16>) -> anyhow::Result<()> {
158-
let store = CertStore::from_pkcs12(super::SERVER_PFX, super::PASSWORD)?;
166+
let store =
167+
CertStore::from_pkcs12(super::SERVER_PFX, super::PASSWORD, Pkcs12Flags::default())?;
159168

160169
let ca_cert_context = store.find_by_subject_str(super::CA_SUBJECT)?;
161170
let ca_cert = ca_cert_context.first().unwrap();

tests/test_find.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use rustls_cng::store::CertStore;
1+
use rustls_cng::store::{CertStore, Pkcs12Flags};
22

33
const PFX: &[u8] = include_bytes!("assets/rustls-ec.p12");
44
const PASSWORD: &str = "changeit";
55

66
#[test]
77
fn test_find_by_subject_str() {
8-
let store = CertStore::from_pkcs12(PFX, PASSWORD).expect("Cannot open cert store");
8+
let store = CertStore::from_pkcs12(PFX, PASSWORD, Pkcs12Flags::default())
9+
.expect("Cannot open cert store");
910

1011
let context = store
1112
.find_by_subject_str("rustls")
@@ -17,7 +18,8 @@ fn test_find_by_subject_str() {
1718

1819
#[test]
1920
fn test_find_by_subject_name() {
20-
let store = CertStore::from_pkcs12(PFX, PASSWORD).expect("Cannot open cert store");
21+
let store = CertStore::from_pkcs12(PFX, PASSWORD, Pkcs12Flags::default())
22+
.expect("Cannot open cert store");
2123

2224
let context = store
2325
.find_by_subject_name("CN=rustls-ec")
@@ -29,7 +31,8 @@ fn test_find_by_subject_name() {
2931

3032
#[test]
3133
fn test_find_by_issuer_str() {
32-
let store = CertStore::from_pkcs12(PFX, PASSWORD).expect("Cannot open cert store");
34+
let store = CertStore::from_pkcs12(PFX, PASSWORD, Pkcs12Flags::default())
35+
.expect("Cannot open cert store");
3336

3437
let context = store
3538
.find_by_issuer_str("Inforce")
@@ -41,7 +44,8 @@ fn test_find_by_issuer_str() {
4144

4245
#[test]
4346
fn test_find_by_issuer_name() {
44-
let store = CertStore::from_pkcs12(PFX, PASSWORD).expect("Cannot open cert store");
47+
let store = CertStore::from_pkcs12(PFX, PASSWORD, Pkcs12Flags::default())
48+
.expect("Cannot open cert store");
4549

4650
let context = store
4751
.find_by_issuer_name("O=Inforce Technologies, CN=Inforce Technologies CA")
@@ -53,7 +57,8 @@ fn test_find_by_issuer_name() {
5357

5458
#[test]
5559
fn test_find_by_hash() {
56-
let store = CertStore::from_pkcs12(PFX, PASSWORD).expect("Cannot open cert store");
60+
let store = CertStore::from_pkcs12(PFX, PASSWORD, Pkcs12Flags::default())
61+
.expect("Cannot open cert store");
5762

5863
let sha1 = [
5964
0x66, 0xBF, 0xFD, 0xE5, 0xD2, 0x9D, 0x57, 0x97, 0x1B, 0x17, 0xBB, 0x81, 0x5D, 0x7A, 0xF8,
@@ -65,7 +70,8 @@ fn test_find_by_hash() {
6570

6671
#[test]
6772
fn test_find_by_hash256() {
68-
let store = CertStore::from_pkcs12(PFX, PASSWORD).expect("Cannot open cert store");
73+
let store = CertStore::from_pkcs12(PFX, PASSWORD, Pkcs12Flags::default())
74+
.expect("Cannot open cert store");
6975

7076
let sha256 = [
7177
0xC9, 0x7C, 0xD6, 0xA1, 0x3F, 0xF6, 0xBD, 0xF6, 0xD4, 0xE2, 0xFB, 0x0E, 0xCD, 0x74, 0x2F,
@@ -79,7 +85,8 @@ fn test_find_by_hash256() {
7985

8086
#[test]
8187
fn test_find_all() {
82-
let store = CertStore::from_pkcs12(PFX, PASSWORD).expect("Cannot open cert store");
88+
let store = CertStore::from_pkcs12(PFX, PASSWORD, Pkcs12Flags::default())
89+
.expect("Cannot open cert store");
8390

8491
let context = store.find_all().unwrap().into_iter().next();
8592
assert!(context.is_some());

tests/test_sign.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
use rustls::crypto::{SignatureScheme, SigningKey};
2-
use rustls_cng::{signer::CngSigningKey, store::CertStore};
2+
use rustls_cng::{
3+
signer::CngSigningKey,
4+
store::{CertStore, Pkcs12Flags},
5+
};
36

47
const PFX: &[u8] = include_bytes!("assets/rustls-ec.p12");
58
const PASSWORD: &str = "changeit";
69
const MESSAGE: &str = "Security is our business";
710

811
#[test]
912
fn test_sign() {
10-
let store = CertStore::from_pkcs12(PFX, PASSWORD).expect("Cannot open cert store");
13+
let store = CertStore::from_pkcs12(PFX, PASSWORD, Pkcs12Flags::default())
14+
.expect("Cannot open cert store");
1115

1216
let context = store
1317
.find_by_subject_str("rustls")

0 commit comments

Comments
 (0)