Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kerberos smart card credentials handling #143

Merged
merged 86 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from 85 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
bae70b9
feat(sspi): add scard feature;
TheBestTvarynka Jul 16, 2023
f59c379
fix(ntlm): warnings
TheBestTvarynka Jul 16, 2023
ff9b339
feat(ffi): add scrd feature
TheBestTvarynka Jul 16, 2023
2159b19
feat(kerberos): implement certificate extraction by thumbprint
TheBestTvarynka Jul 17, 2023
752de6c
feat(sspi): builders: implement the transform method for accept secur…
TheBestTvarynka Jul 17, 2023
49cbaa0
feat(sspi): builders: implement the transform method for acquire cred…
TheBestTvarynka Jul 17, 2023
5819366
feat(sspi): builders: implement the transform method for init sec con…
TheBestTvarynka Jul 17, 2023
0f64ac4
feat(auth_identity): add and implement Credetials/CredentialsBuffers
TheBestTvarynka Jul 17, 2023
ad4c612
feat(sspi): negotiate: improved credentials passing: now we can pass …
TheBestTvarynka Jul 17, 2023
99b5767
feat(sspi): kerberos: improved credentials passing: now we can pass r…
TheBestTvarynka Jul 17, 2023
bbe8c67
fix(sspi): builders: accept_sec_context: change lifetime too in full_…
TheBestTvarynka Jul 18, 2023
3291998
fix(sspi): builder: acq_cred_handle: change lifetime too in full_tran…
TheBestTvarynka Jul 18, 2023
01f59ec
fix(sspi): builder: init_sec_context: change lifetime too in full_tra…
TheBestTvarynka Jul 18, 2023
28ceadd
fix(sspi): negotiate: mutation and references errors
TheBestTvarynka Jul 18, 2023
ba8d7fa
feat(sspi): credssp: improved credentials passing: now we can pass re…
TheBestTvarynka Jul 18, 2023
9c71619
feat(sspi): sspi_cred_ssp: improved credentials passing: now we can p…
TheBestTvarynka Jul 18, 2023
c913293
feat(ffi): add support of the Credentials/CredentialsBuffers instead …
TheBestTvarynka Jul 18, 2023
b78f390
feat(sspi): auth_identity: add username field to smart card creds;
TheBestTvarynka Jul 21, 2023
075ed41
feat(ffi): handle smart card creds in tsssp;
TheBestTvarynka Jul 27, 2023
e9b12c0
feat(ffi): small refactoring
TheBestTvarynka Jul 27, 2023
5f76d84
feat(ffi): format code;
TheBestTvarynka Jul 27, 2023
53c5e78
feat(cargo.toml): temporary replaces picky-* crates with local ones;
TheBestTvarynka Aug 9, 2023
845832e
feat(credssp): ts_request: improve credentials encoding/decoding: use…
TheBestTvarynka Aug 9, 2023
3591304
feat(credssp): ts_request: tests: improved tests according to the cre…
TheBestTvarynka Aug 9, 2023
195fdaa
feat(sspi): refactor cert_utils and smart card credentials;
TheBestTvarynka Aug 16, 2023
351d746
feat(credssp): improved credentials encryption/decryption;
TheBestTvarynka Aug 9, 2023
ab36b1e
feat(sspi): credssp: format code. improve credentials encoding: remov…
TheBestTvarynka Aug 13, 2023
2699233
feat(sspi): auth_identity: add card_name, container_name, and csp_nam…
TheBestTvarynka Aug 13, 2023
999c400
fix(ffi): auth_identity: compilation error in smart card credentials;
TheBestTvarynka Aug 13, 2023
eaadcb5
feat(sspi): cert_utils: implement smart card info (key container name…
TheBestTvarynka Aug 13, 2023
9407775
feat(sspi): cert_utils: implememt user name extraction from the smart…
TheBestTvarynka Aug 13, 2023
12f50af
feat(ffi): auth_identity: improve credentials gathering;
TheBestTvarynka Aug 13, 2023
88c1062
feat(ffi): format code;
TheBestTvarynka Aug 13, 2023
29cf34b
feat(sspi): cert_utils: format code;
TheBestTvarynka Aug 13, 2023
6a3240c
feat(sspi): cert_utils: improve logging;
TheBestTvarynka Aug 14, 2023
ff77833
fix(sspi): cert_utils: smart card info finalizing;
TheBestTvarynka Aug 14, 2023
ab18461
fix(sspi): credssp: ts_request: smart card credentials encoding;
TheBestTvarynka Aug 14, 2023
9fd02e7
feat(ffi): auth_identity: improve smart card creds handling;
TheBestTvarynka Aug 14, 2023
4f46ddd
feat(sspi): auth_identity: add private_key_file_index field;
TheBestTvarynka Aug 14, 2023
bf56850
feat(sspi): cert_utils: implement private_key_file_index calculation;
TheBestTvarynka Aug 14, 2023
464641f
feat(ffi): auth_identity: improve smart card creds handling;
TheBestTvarynka Aug 14, 2023
a0d7131
feat(sspi): auth_identity: smart card: make scard name optional;
TheBestTvarynka Aug 15, 2023
bb9f5d0
feat(sspi): credssp: improve smart card creds writing;
TheBestTvarynka Aug 15, 2023
055f2e6
feat(ffi): auth_identity: improve smart card credentials handlings;
TheBestTvarynka Aug 15, 2023
df7d1f0
feat(ffi): fix clippy warnings;
TheBestTvarynka Aug 15, 2023
fdbc5fc
feat(sspi): negotiate: fix clippy warnings;
TheBestTvarynka Aug 15, 2023
0880fc0
feat(sspi): builders: fix clippy warnings;
TheBestTvarynka Aug 15, 2023
6de545b
fix(sspi): cert_utils: private_key_index calculation;
TheBestTvarynka Aug 15, 2023
032e1c6
fix(ffi): auth_identity: smart card creds handling: add null byte to …
TheBestTvarynka Aug 15, 2023
d7d949a
feat(sspi): return error from SspiEx::custom_set_auth_identity method;
TheBestTvarynka Aug 15, 2023
622e6d4
feat(sspi): utils: improve string_to_utf16 function;
TheBestTvarynka Aug 15, 2023
75edea3
feat(sspi): auth_identity: add more doc commets. improve conversion;
TheBestTvarynka Aug 15, 2023
c345505
feat(sspi): credssp: small refactoring;
TheBestTvarynka Aug 15, 2023
0707394
fix(sspi): pku2u: return Result from custom_set_auth_identity function;
TheBestTvarynka Aug 16, 2023
dd3f9c9
fix(sspi): kerberos: return Result from custom_set_auth_identity func…
TheBestTvarynka Aug 16, 2023
0614542
feat(sspi): negotiate: small refactoring;
TheBestTvarynka Aug 15, 2023
8f02d9c
feat(sspi): builders: small refactoring. add more comments;
TheBestTvarynka Aug 15, 2023
1171daa
feat(sspi): ntlm: small refactoring;
TheBestTvarynka Aug 15, 2023
30ccb2d
feat(sspi): credssp: small refactoring. improve conditional compilation;
TheBestTvarynka Aug 15, 2023
3b086f4
feat(sspi): cert_utils: code and tests refactoring. add more comments…
TheBestTvarynka Aug 15, 2023
df69f56
feat(ffi): sec_handle: refactor acquire credentials handle;
TheBestTvarynka Aug 15, 2023
9bd7bd3
feat(ffi): utils: remove uneeded function str_to_utf16_bytes;
TheBestTvarynka Aug 15, 2023
ab38e33
feat(ffi): auth_identity: small refactoring;
TheBestTvarynka Aug 15, 2023
5b42210
feat(sspi): Cargo.toml: remove default features;
TheBestTvarynka Aug 15, 2023
793af2e
sspi: refactoring;
TheBestTvarynka Aug 16, 2023
2159a7e
feat(sspi): cert_utils: improved upn extraction from certificate;
TheBestTvarynka Aug 17, 2023
3e5ce34
feat(sspi): format code;
TheBestTvarynka Aug 17, 2023
12e0645
feat(ffi): remove default features. improve conditional compilation;
TheBestTvarynka Aug 17, 2023
4c90b88
feat(sspi): cert_utils: improve conditional compilation;
TheBestTvarynka Aug 18, 2023
4652e80
feat(ffi): auth_identity: improve conditional compilation;
TheBestTvarynka Aug 18, 2023
33aab3e
feat(sspi): update picky-* dependencies: replace local paths with git…
TheBestTvarynka Aug 18, 2023
bcb1c3c
feat(sspi): small refactoring;
TheBestTvarynka Aug 18, 2023
d2d25cb
feat(ffi): format code;
TheBestTvarynka Aug 18, 2023
671a000
revert rust toolchain version: 1.71.0 -> 1.71.1;
TheBestTvarynka Aug 18, 2023
d20660d
feat(sspi): add support of smart card credentials in the credssp clie…
TheBestTvarynka Aug 23, 2023
75845a4
sspi: update picky-* dependencies
TheBestTvarynka Aug 23, 2023
b89ff48
fix: wasm-testcompile compilation
TheBestTvarynka Aug 23, 2023
9e3eb9d
feat(ffi): add comment about SEC_WINNT_AUTH_IDENTITY_UNICODE flag
TheBestTvarynka Aug 23, 2023
ba71154
feat(ffi): revert and improve auth_data_to_identity_buffers function
TheBestTvarynka Aug 25, 2023
eafbbda
fix(ffi): replace auth_data_to_identity_buffers_q/w with auth_data_to…
TheBestTvarynka Aug 25, 2023
9046202
feat(ffi): add comment about auth_data_to_identity_buffers function
TheBestTvarynka Aug 25, 2023
0455a71
fix(sspi): cert_utils module conditional compilation
TheBestTvarynka Aug 25, 2023
49e70c0
sspi: update picky-* dependencies
TheBestTvarynka Aug 25, 2023
55d2f9c
feat(ffi): improve smart card credentials detection
TheBestTvarynka Aug 25, 2023
0de5681
Merge branch 'kerberos-smart-card-credentials' of ssh://jira.dev.loca…
TheBestTvarynka Aug 25, 2023
ade277b
feat(ffi): improve smart card credentials handling. format code
TheBestTvarynka Aug 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ network_client = ["dep:reqwest", "dep:portpicker"]
dns_resolver = ["dep:trust-dns-resolver", "dep:tokio"]
# TSSSP should be used only on Windows as a native CREDSSP replacement
tsssp = ["dep:rustls"]
# Turns on Kerberos smart card login (available only on Windows and users WinSCard API)
scard = ["dep:pcsc"]

[dependencies]
byteorder = "1.2.7"
Expand All @@ -46,20 +48,23 @@ serde = "1.0"
serde_derive = "1.0"
url = "2.2.2"
reqwest = { version = "0.11", features = ["blocking", "rustls-tls", "rustls-tls-native-roots"], optional = true, default-features = false }
picky = { version = "7.0.0-rc.4", default-features = false }
picky-krb = "0.6.0"
picky-asn1 = { version = "0.7.1", features = ["chrono_conversion"] }
picky-asn1-der = "0.4.0"
picky-asn1-x509 = { version = "0.9.0", features = ["pkcs7"] }

picky = { version = "7.0.0-rc.8", default-features = false }
picky-asn1 = { version = "0.8.0", features = ["chrono_conversion"] }
picky-asn1-der = "0.4.1"
picky-asn1-x509 = { version = "0.12.0", features = ["pkcs7"] }
picky-krb = "0.8.0"

oid = "0.2.1"
uuid = { version = "1.1", features = ["v4"] }
uuid = { version = "1.3", features = ["v4"] }
trust-dns-resolver = { version = "0.21.2", optional = true }
portpicker = { version = "0.1.1", optional = true }
num-bigint-dig = "0.8.1"
tracing = "0.1.37"
rustls = { version = "0.20.7", features = ["dangerous_configuration"], optional = true }
zeroize = { version = "1.5.7", features = ["zeroize_derive"] }
tokio = { version = "1.1", features = ["time", "rt"], optional = true }
pcsc = { version = "2.8.0", optional = true }

[target.'cfg(windows)'.dependencies]
winreg = "0.10"
Expand All @@ -75,3 +80,4 @@ tokio = { version = "1.1", features = ["time", "rt"] }
[dev-dependencies]
static_assertions = "1.1"
whoami = "0.5"
picky = { version = "7.0.0-rc.8", features = ["x509"] }
1 change: 1 addition & 0 deletions ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ crate-type = ["cdylib"]
[features]
default = []
tsssp = ["sspi/tsssp"]
scard = ["sspi/scard"]
CBenoit marked this conversation as resolved.
Show resolved Hide resolved

[dependencies]
cfg-if = "0.1"
Expand Down
4 changes: 2 additions & 2 deletions ffi/src/sec_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use sspi::kerberos::config::KerberosConfig;
use sspi::network_client::reqwest_network_client::{RequestClientFactory, ReqwestNetworkClient};
use sspi::ntlm::NtlmConfig;
use sspi::{
kerberos, negotiate, ntlm, pku2u, AuthIdentityBuffers, ClientRequestFlags, DataRepresentation, Error, ErrorKind,
kerberos, negotiate, ntlm, pku2u, ClientRequestFlags, CredentialsBuffers, DataRepresentation, Error, ErrorKind,
Kerberos, Negotiate, NegotiateConfig, Ntlm, Result, Secret, Sspi, SspiImpl,
};
#[cfg(target_os = "windows")]
Expand Down Expand Up @@ -82,7 +82,7 @@ pub type PCredHandle = *mut SecHandle;
pub type PCtxtHandle = *mut SecHandle;

pub struct CredentialsHandle {
pub credentials: AuthIdentityBuffers,
pub credentials: CredentialsBuffers,
pub security_package_name: String,
pub attributes: CredentialsAttributes,
}
Expand Down
173 changes: 139 additions & 34 deletions ffi/src/sec_winnt_auth_identity.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
use std::slice::from_raw_parts;

use libc::{c_char, c_void};
use sspi::{AuthIdentityBuffers, Error, ErrorKind, Result};
#[cfg(windows)]
use sspi::Secret;
#[cfg(feature = "scard")]
use sspi::SmartCardIdentityBuffers;
use sspi::{AuthIdentityBuffers, CredentialsBuffers, Error, ErrorKind, Result};
#[cfg(windows)]
use symbol_rename_macro::rename_symbol;
#[cfg(feature = "tsssp")]
use windows_sys::Win32::Security::Authentication::Identity::SspiIsAuthIdentityEncrypted;
#[cfg(feature = "scard")]
use winapi::um::wincred::CredIsMarshaledCredentialW;

use crate::sspi_data_types::{SecWChar, SecurityStatus};
use crate::utils::{c_w_str_to_string, into_raw_ptr, raw_str_into_bytes};
Expand Down Expand Up @@ -158,25 +166,39 @@ pub unsafe fn get_auth_data_identity_version_and_flags(p_auth_data: *const c_voi
}
}

// This function determines what format credentials have: ASCII or UNICODE,
// and then calls an appropriate raw credentials handler function.
// Why do we need such a function:
// Actually, on Linux FreeRDP can pass UNICODE credentials into the AcquireCredentialsHandleA function.
// So, we need to be able to handle any credentials format in the AcquireCredentialsHandleA/W functions.
pub unsafe fn auth_data_to_identity_buffers(
security_package_name: &str,
p_auth_data: *const c_void,
package_list: &mut Option<String>,
) -> Result<AuthIdentityBuffers> {
) -> Result<CredentialsBuffers> {
let (_, auth_flags) = get_auth_data_identity_version_and_flags(p_auth_data);

if (auth_flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0 {
auth_data_to_identity_buffers_w(security_package_name, p_auth_data, package_list)
} else {
let rawcreds = std::slice::from_raw_parts(p_auth_data as *const u8, 128);
debug!(?rawcreds);

#[cfg(feature = "tsssp")]
if SspiIsAuthIdentityEncrypted(p_auth_data) != 0 {
let credssp_cred = p_auth_data.cast::<CredSspCred>().as_ref().unwrap();
return unpack_sec_winnt_auth_identity_ex2_w(credssp_cred.p_spnego_cred);
}

if (auth_flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0 {
auth_data_to_identity_buffers_a(security_package_name, p_auth_data, package_list)
} else {
auth_data_to_identity_buffers_w(security_package_name, p_auth_data, package_list)
}
}

pub unsafe fn auth_data_to_identity_buffers_a(
_security_package_name: &str,
p_auth_data: *const c_void,
package_list: &mut Option<String>,
) -> Result<AuthIdentityBuffers> {
) -> Result<CredentialsBuffers> {
#[cfg(feature = "tsssp")]
if _security_package_name == sspi::credssp::sspi_cred_ssp::PKG_NAME {
let credssp_cred = p_auth_data.cast::<CredSspCred>().as_ref().unwrap();
Expand All @@ -197,26 +219,26 @@ pub unsafe fn auth_data_to_identity_buffers_a(
.to_string(),
);
}
Ok(AuthIdentityBuffers {
Ok(CredentialsBuffers::AuthIdentity(AuthIdentityBuffers {
user: raw_str_into_bytes((*auth_data).user, (*auth_data).user_length as usize),
domain: raw_str_into_bytes((*auth_data).domain, (*auth_data).domain_length as usize),
password: raw_str_into_bytes((*auth_data).password, (*auth_data).password_length as usize).into(),
})
}))
} else {
let auth_data = p_auth_data.cast::<SecWinntAuthIdentityA>();
Ok(AuthIdentityBuffers {
Ok(CredentialsBuffers::AuthIdentity(AuthIdentityBuffers {
user: raw_str_into_bytes((*auth_data).user, (*auth_data).user_length as usize),
domain: raw_str_into_bytes((*auth_data).domain, (*auth_data).domain_length as usize),
password: raw_str_into_bytes((*auth_data).password, (*auth_data).password_length as usize).into(),
})
}))
}
}

pub unsafe fn auth_data_to_identity_buffers_w(
_security_package_name: &str,
p_auth_data: *const c_void,
package_list: &mut Option<String>,
) -> Result<AuthIdentityBuffers> {
) -> Result<CredentialsBuffers> {
#[cfg(feature = "tsssp")]
if _security_package_name == sspi::credssp::sspi_cred_ssp::PKG_NAME {
let credssp_cred = p_auth_data.cast::<CredSspCred>().as_ref().unwrap();
Expand All @@ -234,26 +256,44 @@ pub unsafe fn auth_data_to_identity_buffers_w(
(*auth_data).package_list_length as usize,
)));
}
Ok(AuthIdentityBuffers {
user: raw_str_into_bytes((*auth_data).user as *const _, (*auth_data).user_length as usize * 2),
let user = raw_str_into_bytes((*auth_data).user as *const _, (*auth_data).user_length as usize * 2);
let password = raw_str_into_bytes(
(*auth_data).password as *const _,
(*auth_data).password_length as usize * 2,
)
.into();

// only marshaled smart card creds starts with '@' char
#[cfg(feature = "scard")]
if user[0] == b'@' && CredIsMarshaledCredentialW(user.as_ptr() as *const _) != 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calling CredIsMarshaledCredentialW should be enough, it checks for @@ under the hood anyway. maybe the only potential issue is that CredIsMarshaledCredentialW could return true for types other than 1

Copy link
Collaborator Author

@TheBestTvarynka TheBestTvarynka Aug 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

return handle_smart_card_creds(user, password);
}

Ok(CredentialsBuffers::AuthIdentity(AuthIdentityBuffers {
user,
domain: raw_str_into_bytes((*auth_data).domain as *const _, (*auth_data).domain_length as usize * 2),
password: raw_str_into_bytes(
(*auth_data).password as *const _,
(*auth_data).password_length as usize * 2,
)
.into(),
})
password,
}))
} else {
let auth_data = p_auth_data.cast::<SecWinntAuthIdentityW>();
Ok(AuthIdentityBuffers {
user: raw_str_into_bytes((*auth_data).user as *const _, (*auth_data).user_length as usize * 2),
let user = raw_str_into_bytes((*auth_data).user as *const _, (*auth_data).user_length as usize * 2);
let password = raw_str_into_bytes(
(*auth_data).password as *const _,
(*auth_data).password_length as usize * 2,
)
.into();

// only marshaled smart card creds starts with '@' char
#[cfg(feature = "scard")]
if user[0] == b'@' && CredIsMarshaledCredentialW(user.as_ptr() as *const _) != 0 {
return handle_smart_card_creds(user, password);
}

Ok(CredentialsBuffers::AuthIdentity(AuthIdentityBuffers {
user,
domain: raw_str_into_bytes((*auth_data).domain as *const _, (*auth_data).domain_length as usize * 2),
password: raw_str_into_bytes(
(*auth_data).password as *const _,
(*auth_data).password_length as usize * 2,
)
.into(),
})
password,
}))
}
}

Expand Down Expand Up @@ -287,10 +327,9 @@ unsafe fn get_sec_winnt_auth_identity_ex2_size(p_auth_data: *const c_void) -> u3
}

#[cfg(target_os = "windows")]
pub unsafe fn unpack_sec_winnt_auth_identity_ex2_a(p_auth_data: *const c_void) -> Result<AuthIdentityBuffers> {
pub unsafe fn unpack_sec_winnt_auth_identity_ex2_a(p_auth_data: *const c_void) -> Result<CredentialsBuffers> {
use std::ptr::null_mut;

use sspi::Secret;
use windows_sys::Win32::Security::Credentials::{CredUnPackAuthenticationBufferA, CRED_PACK_PROTECTED_CREDENTIALS};

if p_auth_data.is_null() {
Expand Down Expand Up @@ -364,22 +403,78 @@ pub unsafe fn unpack_sec_winnt_auth_identity_ex2_a(p_auth_data: *const c_void) -
password.as_mut().pop();
auth_identity_buffers.password = password;

Ok(auth_identity_buffers)
Ok(CredentialsBuffers::AuthIdentity(auth_identity_buffers))
}

#[cfg(not(target_os = "windows"))]
pub fn unpack_sec_winnt_auth_identity_ex2_w(_p_auth_data: *const c_void) -> Result<AuthIdentityBuffers> {
pub fn unpack_sec_winnt_auth_identity_ex2_w(_p_auth_data: *const c_void) -> Result<CredentialsBuffers> {
Err(Error::new(
ErrorKind::UnsupportedFunction,
"SecWinntIdentityEx2 is not supported on non Windows systems",
))
}

#[cfg(feature = "scard")]
#[instrument(level = "trace", ret)]
unsafe fn handle_smart_card_creds(mut username: Vec<u8>, password: Secret<Vec<u8>>) -> Result<CredentialsBuffers> {
use std::ptr::null_mut;

use sspi::cert_utils::{finalize_smart_card_info, SmartCardInfo};
use sspi::string_to_utf16;
use winapi::um::wincred::{CertCredential, CredUnmarshalCredentialW, CERT_CREDENTIAL_INFO};

let mut cred_type = 0;
let mut credential = null_mut();

// add wide null char
username.extend_from_slice(&[0, 0]);

if CredUnmarshalCredentialW(username.as_ptr() as *const _, &mut cred_type, &mut credential) == 0 {
return Err(Error::new(
ErrorKind::NoCredentials,
"Cannot unmarshal smart card credentials",
));
}

if cred_type != CertCredential {
return Err(Error::new(
ErrorKind::NoCredentials,
"Unmarshalled smart card credentials is not CRED_MARSHAL_TYPE::CertCredential",
));
}

let cert_credential = credential.cast::<CERT_CREDENTIAL_INFO>();

let (raw_certificate, certificate) =
sspi::cert_utils::extract_certificate_by_thumbprint(&(*cert_credential).rgbHashOfCert)?;

let username = string_to_utf16(sspi::cert_utils::extract_user_name_from_certificate(&certificate)?);
let SmartCardInfo {
key_container_name,
reader_name,
certificate: _,
csp_name,
private_key_file_index,
} = finalize_smart_card_info(&certificate.tbs_certificate.serial_number.0)?;

let creds = CredentialsBuffers::SmartCard(SmartCardIdentityBuffers {
certificate: raw_certificate,
reader_name: string_to_utf16(reader_name),
pin: password,
username,
card_name: None,
container_name: string_to_utf16(key_container_name),
csp_name: string_to_utf16(csp_name),
private_key_file_index: Some(private_key_file_index),
});

Ok(creds)
}

#[cfg(target_os = "windows")]
pub unsafe fn unpack_sec_winnt_auth_identity_ex2_w(p_auth_data: *const c_void) -> Result<AuthIdentityBuffers> {
pub unsafe fn unpack_sec_winnt_auth_identity_ex2_w(p_auth_data: *const c_void) -> Result<CredentialsBuffers> {
use std::ptr::null_mut;

use sspi::Secret;
use windows_sys::Win32::Security::Credentials::{CredUnPackAuthenticationBufferW, CRED_PACK_PROTECTED_CREDENTIALS};

if p_auth_data.is_null() {
Expand Down Expand Up @@ -431,6 +526,16 @@ pub unsafe fn unpack_sec_winnt_auth_identity_ex2_w(p_auth_data: *const c_void) -
));
}

// only marshaled smart card creds starts with '@' char
#[cfg(feature = "scard")]
if username[0] == b'@' && CredIsMarshaledCredentialW(username.as_ptr() as *const _) != 0 {
// remove null
let new_len = password.as_ref().len() - 2;
password.as_mut().truncate(new_len);

return handle_smart_card_creds(username, password);
}

let mut auth_identity_buffers = AuthIdentityBuffers::default();

// remove null
Expand All @@ -454,7 +559,7 @@ pub unsafe fn unpack_sec_winnt_auth_identity_ex2_w(p_auth_data: *const c_void) -
password.as_mut().truncate(new_len);
auth_identity_buffers.password = password;

Ok(auth_identity_buffers)
Ok(CredentialsBuffers::AuthIdentity(auth_identity_buffers))
}

#[allow(clippy::missing_safety_doc)]
Expand Down
4 changes: 2 additions & 2 deletions ffi/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::slice::from_raw_parts;

use libc::c_char;
use sspi::AuthIdentityBuffers;
use sspi::CredentialsBuffers;

use crate::credentials_attributes::CredentialsAttributes;
use crate::sec_handle::CredentialsHandle;
Expand Down Expand Up @@ -38,7 +38,7 @@ pub unsafe fn raw_str_into_bytes(raw_buffer: *const c_char, len: usize) -> Vec<u

pub unsafe fn transform_credentials_handle<'a>(
credentials_handle: *mut CredentialsHandle,
) -> Option<(AuthIdentityBuffers, &'a str, &'a CredentialsAttributes)> {
) -> Option<(CredentialsBuffers, &'a str, &'a CredentialsAttributes)> {
if credentials_handle.is_null() {
None
} else {
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = "1.71.1"
components = [ "rustfmt", "clippy" ]
components = [ "rustfmt", "clippy" ]
Loading
Loading