mirror of
https://github.com/bitwarden/clients.git
synced 2026-06-13 21:01:11 +08:00
Scaffold win_webauthn [PM-29785] (#20278)
This commit is contained in:
parent
dc888f9acc
commit
21a2be00a8
8
apps/desktop/desktop_native/Cargo.lock
generated
8
apps/desktop/desktop_native/Cargo.lock
generated
@ -4273,6 +4273,14 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
|
||||
|
||||
[[package]]
|
||||
name = "win_webauthn"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"windows 0.62.2",
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
||||
@ -10,6 +10,7 @@ members = [
|
||||
"process_isolation",
|
||||
"proxy",
|
||||
"ssh_agent",
|
||||
"win_webauthn",
|
||||
"windows_plugin_authenticator",
|
||||
]
|
||||
|
||||
|
||||
19
apps/desktop/desktop_native/win_webauthn/Cargo.toml
Normal file
19
apps/desktop/desktop_native/win_webauthn/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "win_webauthn"
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { workspace = true, features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Security",
|
||||
"Win32_Security_Cryptography",
|
||||
"Win32_System_Com",
|
||||
"Win32_System_LibraryLoader",
|
||||
] }
|
||||
windows-core = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
28
apps/desktop/desktop_native/win_webauthn/README.md
Normal file
28
apps/desktop/desktop_native/win_webauthn/README.md
Normal file
@ -0,0 +1,28 @@
|
||||
Rust wrapper for the Windows WebAuthn Library.
|
||||
|
||||
|
||||
Based on [microsoft/webauthn@c3ed95f][webauthn-ref], released in Windows 11
|
||||
November 2025 update.
|
||||
|
||||
[webauthn-ref]: https://github.com/microsoft/webauthn/tree/c3ed95fd7603441a0253c55c14e79239cb556a9f
|
||||
|
||||
# Current Limitations
|
||||
|
||||
In this initial version, there are some limitations that need to be addressed:
|
||||
|
||||
- The `ErrorKind` enum is too broad. The use needs to be audited and more variants should be added for specific error cases.
|
||||
- C structs for use in webauthn.dll functions are defined manually. As of
|
||||
[microsoft/windows-rs@95dfa93](https://github.com/microsoft/windows-rs/tree/95dfa93ce7a004449d5309b36dda9f2300f57db6),
|
||||
these are included in the `windows` crate, but there has not been a released
|
||||
version of that crate since it was added. As soon as it is released, we can
|
||||
update to it.
|
||||
- We are not using the `dwVersion` fields of the structs and are instead
|
||||
hard-coding availability for all the structs as of the Windows 11 passkey plugin
|
||||
authenticator (November 2025). To make this more generally useful, we should
|
||||
read these fields and optionally omit known fields that were introduced in a
|
||||
higher version than `dwVersion` specifies (e.g., by returning an Option<T> for
|
||||
those fields).
|
||||
- End-to-end tests for the plugin authenticator handler code would be good to
|
||||
include. We could consider using a Rust trait to wrap the FFI calls, or to
|
||||
create a DLL from a Rust cdylib that mocks the required webauthn.dll
|
||||
functionality and is called from the tests.
|
||||
2
apps/desktop/desktop_native/win_webauthn/src/api/mod.rs
Normal file
2
apps/desktop/desktop_native/win_webauthn/src/api/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
//! Safe wrappers around raw types and functions for webauthn.dll.
|
||||
mod sys;
|
||||
222
apps/desktop/desktop_native/win_webauthn/src/api/sys/mod.rs
Normal file
222
apps/desktop/desktop_native/win_webauthn/src/api/sys/mod.rs
Normal file
@ -0,0 +1,222 @@
|
||||
//! Raw types for the Windows webauthn.dll library.
|
||||
//! The top-level crate includes types defined in webauthn.h.
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
pub(super) mod plugin;
|
||||
mod util;
|
||||
|
||||
use std::{num::NonZeroU32, ptr::NonNull};
|
||||
|
||||
use windows::core::BOOL;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_COSE_CREDENTIAL_PARAMETER {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
pub(super) dwVersion: u32,
|
||||
/// Well-known credential type specifying a credential to create.
|
||||
pub(super) pwszCredentialType: NonNull<u16>,
|
||||
/// Well-known COSE algorithm specifying the algorithm to use for the credential.
|
||||
pub(super) lAlg: i32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_COSE_CREDENTIAL_PARAMETERS {
|
||||
pub(super) cCredentialParameters: u32,
|
||||
pub(super) pCredentialParameters: *const WEBAUTHN_COSE_CREDENTIAL_PARAMETER,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_CREDENTIAL_ATTESTATION {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
pub(super) dwVersion: u32,
|
||||
|
||||
/// Attestation format type
|
||||
pub(super) pwszFormatType: *const u16, // PCWSTR
|
||||
|
||||
/// Size of cbAuthenticatorData.
|
||||
pub(super) cbAuthenticatorData: u32,
|
||||
/// Authenticator data that was created for this credential.
|
||||
//_Field_size_bytes_(cbAuthenticatorData)
|
||||
pub(super) pbAuthenticatorData: *const u8,
|
||||
|
||||
/// Size of CBOR encoded attestation information
|
||||
/// 0 => encoded as CBOR null value.
|
||||
pub(super) cbAttestation: u32,
|
||||
///Encoded CBOR attestation information
|
||||
// _Field_size_bytes_(cbAttestation)
|
||||
pub(super) pbAttestation: *const u8,
|
||||
|
||||
pub(super) dwAttestationDecodeType: u32,
|
||||
/// Following depends on the dwAttestationDecodeType
|
||||
/// WEBAUTHN_ATTESTATION_DECODE_NONE
|
||||
/// NULL - not able to decode the CBOR attestation information
|
||||
/// WEBAUTHN_ATTESTATION_DECODE_COMMON
|
||||
/// PWEBAUTHN_COMMON_ATTESTATION;
|
||||
pub(super) pvAttestationDecode: *const u8,
|
||||
|
||||
/// The CBOR encoded Attestation Object to be returned to the RP.
|
||||
pub(super) cbAttestationObject: u32,
|
||||
// _Field_size_bytes_(cbAttestationObject)
|
||||
pub(super) pbAttestationObject: *const u8,
|
||||
|
||||
/// The CredentialId bytes extracted from the Authenticator Data.
|
||||
/// Used by Edge to return to the RP.
|
||||
pub(super) cbCredentialId: u32,
|
||||
// _Field_size_bytes_(cbCredentialId)
|
||||
pub(super) pbCredentialId: *const u8,
|
||||
|
||||
//
|
||||
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2
|
||||
/// Since VERSION 2
|
||||
pub(super) Extensions: WEBAUTHN_EXTENSIONS,
|
||||
|
||||
//
|
||||
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3
|
||||
/// One of the WEBAUTHN_CTAP_TRANSPORT_* bits will be set corresponding to
|
||||
/// the transport that was used.
|
||||
pub(super) dwUsedTransport: u32,
|
||||
|
||||
//
|
||||
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4
|
||||
pub(super) bEpAtt: BOOL,
|
||||
pub(super) bLargeBlobSupported: BOOL,
|
||||
pub(super) bResidentKey: BOOL,
|
||||
|
||||
//
|
||||
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_5
|
||||
pub(super) bPrfEnabled: BOOL,
|
||||
|
||||
//
|
||||
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_6
|
||||
pub(super) cbUnsignedExtensionOutputs: u32,
|
||||
// _Field_size_bytes_(cbUnsignedExtensionOutputs)
|
||||
pub(super) pbUnsignedExtensionOutputs: *const u8,
|
||||
|
||||
//
|
||||
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_7
|
||||
pub(super) pHmacSecret: *const WEBAUTHN_HMAC_SECRET_SALT,
|
||||
|
||||
/// ThirdPartyPayment Credential or not.
|
||||
pub(super) bThirdPartyPayment: BOOL,
|
||||
|
||||
//
|
||||
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_8
|
||||
/// Multiple WEBAUTHN_CTAP_TRANSPORT_* bits will be set corresponding to
|
||||
/// the transports that are supported.
|
||||
pub(super) dwTransports: u32,
|
||||
|
||||
/// UTF-8 encoded JSON serialization of the client data.
|
||||
pub(super) cbClientDataJSON: u32,
|
||||
// _Field_size_bytes_(cbClientDataJSON)
|
||||
pub(super) pbClientDataJSON: *const u8,
|
||||
|
||||
/// UTF-8 encoded JSON serialization of the RegistrationResponse.
|
||||
pub(super) cbRegistrationResponseJSON: u32,
|
||||
// _Field_size_bytes_(cbRegistrationResponseJSON)
|
||||
pub(super) pbRegistrationResponseJSON: *const u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_CREDENTIAL_EX {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
pub(super) dwVersion: u32,
|
||||
/// Size of pbID.
|
||||
pub(super) cbId: u32,
|
||||
/// Unique ID for this particular credential.
|
||||
pub(super) pbId: *const u8,
|
||||
/// Well-known credential type specifying what this particular credential is.
|
||||
pub(super) pwszCredentialType: *const u16,
|
||||
/// Transports. 0 implies no transport restrictions.
|
||||
pub(super) dwTransports: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_CREDENTIAL_LIST {
|
||||
pub(super) cCredentials: u32,
|
||||
pub(super) ppCredentials: *const *const WEBAUTHN_CREDENTIAL_EX,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_EXTENSION {
|
||||
pwszExtensionIdentifier: *const u16,
|
||||
cbExtension: u32,
|
||||
pvExtension: *mut u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_EXTENSIONS {
|
||||
pub(super) cExtensions: u32,
|
||||
// _Field_size_(cExtensions)
|
||||
pub(super) pExtensions: *const WEBAUTHN_EXTENSION,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub(super) struct WEBAUTHN_HMAC_SECRET_SALT {
|
||||
/// Size of pbFirst.
|
||||
_cbFirst: u32,
|
||||
// _Field_size_bytes_(cbFirst)
|
||||
/// Required
|
||||
_pbFirst: *mut u8,
|
||||
|
||||
/// Size of pbSecond.
|
||||
_cbSecond: u32,
|
||||
// _Field_size_bytes_(cbSecond)
|
||||
_pbSecond: *mut u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_RP_ENTITY_INFORMATION {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
/// This field is required and should be set to CURRENT_VERSION above.
|
||||
pub(super) dwVersion: u32,
|
||||
|
||||
/// Identifier for the RP. This field is required.
|
||||
pub(super) pwszId: NonNull<u16>, // PCWSTR
|
||||
|
||||
/// Contains the friendly name of the Relying Party, such as "Acme
|
||||
/// Corporation", "Widgets Inc" or "Awesome Site".
|
||||
///
|
||||
/// This member is deprecated in WebAuthn Level 3 because many clients do not display it, but
|
||||
/// it remains a required dictionary member for backwards compatibility. Relying
|
||||
/// Parties MAY, as a safe default, set this equal to the RP ID.
|
||||
pub(super) pwszName: *const u16, // PCWSTR
|
||||
|
||||
/// Optional URL pointing to RP's logo.
|
||||
///
|
||||
/// This field was removed in WebAuthn Level 2. Keeping this here for proper struct sizing.
|
||||
#[deprecated]
|
||||
_pwszIcon: *const u16, // PCWSTR
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(super) struct WEBAUTHN_USER_ENTITY_INFORMATION {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
/// This field is required and should be set to CURRENT_VERSION above.
|
||||
pub(super) dwVersion: u32,
|
||||
|
||||
/// Identifier for the User. This field is required.
|
||||
pub(super) cbId: NonZeroU32, // DWORD
|
||||
pub(super) pbId: NonNull<u8>, // PBYTE
|
||||
|
||||
/// Contains a detailed name for this account, such as "john.p.smith@example.com".
|
||||
pub(super) pwszName: NonNull<u16>, // PCWSTR
|
||||
|
||||
/// Optional URL that can be used to retrieve an image containing the user's current avatar,
|
||||
/// or a data URI that contains the image data.
|
||||
#[deprecated]
|
||||
pub(super) pwszIcon: Option<NonNull<u16>>, // PCWSTR
|
||||
|
||||
/// Contains the friendly name associated with the user account by the Relying Party, such as
|
||||
/// "John P. Smith".
|
||||
pub(super) pwszDisplayName: NonNull<u16>, // PCWSTR
|
||||
}
|
||||
565
apps/desktop/desktop_native/win_webauthn/src/api/sys/plugin.rs
Normal file
565
apps/desktop/desktop_native/win_webauthn/src/api/sys/plugin.rs
Normal file
@ -0,0 +1,565 @@
|
||||
//! Types from webauthn.dll as defined in webauthnplugin.h and pluginauthenticator.h.
|
||||
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use windows::{
|
||||
core::{BOOL, GUID, HRESULT},
|
||||
Win32::{Foundation::HWND, Security::Cryptography::BCRYPT_KEY_BLOB},
|
||||
};
|
||||
|
||||
use super::{
|
||||
util::webauthn_call, WEBAUTHN_COSE_CREDENTIAL_PARAMETERS, WEBAUTHN_CREDENTIAL_ATTESTATION,
|
||||
WEBAUTHN_CREDENTIAL_LIST, WEBAUTHN_RP_ENTITY_INFORMATION, WEBAUTHN_USER_ENTITY_INFORMATION,
|
||||
};
|
||||
|
||||
/// Plugin lock status enum as defined in the IDL
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum PLUGIN_LOCK_STATUS {
|
||||
PluginLocked = 0,
|
||||
PluginUnlocked = 1,
|
||||
}
|
||||
|
||||
/// Windows WebAuthn Authenticator Options structure
|
||||
/// Header File Name: _WEBAUTHN_CTAPCBOR_AUTHENTICATOR_OPTIONS
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct WEBAUTHN_CTAPCBOR_AUTHENTICATOR_OPTIONS {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
pub(in crate::api) dwVersion: u32,
|
||||
/// "up" option: +1=TRUE, 0=Not defined, -1=FALSE
|
||||
pub(in crate::api) lUp: i32,
|
||||
/// "uv" option: +1=TRUE, 0=Not defined, -1=FALSE
|
||||
pub(in crate::api) lUv: i32,
|
||||
/// "rk" option: +1=TRUE, 0=Not defined, -1=FALSE
|
||||
pub(in crate::api) lRequireResidentKey: i32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub(in crate::api) struct WEBAUTHN_CTAPCBOR_ECC_PUBLIC_KEY {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
pub(in crate::api) _dwVersion: u32,
|
||||
|
||||
/// Key type
|
||||
pub(in crate::api) _lKty: i32,
|
||||
|
||||
/// Hash Algorithm: ES256, ES384, ES512
|
||||
pub(in crate::api) _lAlg: i32,
|
||||
|
||||
/// Curve
|
||||
pub(in crate::api) _lCrv: i32,
|
||||
|
||||
/// Size of "x" (X Coordinate)
|
||||
pub(in crate::api) _cbX: u32,
|
||||
|
||||
/// "x" (X Coordinate) data. Big Endian.
|
||||
pub(in crate::api) _pbX: *const u8,
|
||||
|
||||
/// Size of "y" (Y Coordinate)
|
||||
pub(in crate::api) _cbY: u32,
|
||||
|
||||
/// "y" (Y Coordinate) data. Big Endian.
|
||||
pub(in crate::api) _pbY: *const u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(in crate::api) struct WEBAUTHN_CTAPCBOR_GET_ASSERTION_REQUEST {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
pub(in crate::api) dwVersion: u32,
|
||||
/// RP ID (after UTF-8 to Unicode conversion)
|
||||
pub(in crate::api) pwszRpId: *const u16,
|
||||
/// Input RP ID size (raw UTF-8 bytes before conversion)
|
||||
pub(in crate::api) cbRpId: u32,
|
||||
/// Raw UTF-8 bytes before conversion to UTF-16 in pwszRpId. These are the
|
||||
/// bytes to be hashed in the Authenticator Data.
|
||||
pub(in crate::api) pbRpId: *const u8,
|
||||
/// Client Data Hash size
|
||||
pub(in crate::api) cbClientDataHash: u32,
|
||||
/// Client Data Hash data
|
||||
pub(in crate::api) pbClientDataHash: *const u8,
|
||||
/// Credentials used for inclusion
|
||||
pub(in crate::api) CredentialList: WEBAUTHN_CREDENTIAL_LIST,
|
||||
/// CBOR extensions map size
|
||||
pub(in crate::api) cbCborExtensionsMap: u32,
|
||||
/// CBOR extensions map data
|
||||
pub(in crate::api) pbCborExtensionsMap: *const u8,
|
||||
/// Authenticator Options (Optional)
|
||||
pub(in crate::api) pAuthenticatorOptions: *const WEBAUTHN_CTAPCBOR_AUTHENTICATOR_OPTIONS,
|
||||
|
||||
// Pin Auth (Optional)
|
||||
/// Zero length PinAuth is included in the request
|
||||
pub(in crate::api) fEmptyPinAuth: BOOL,
|
||||
/// Pin Auth size
|
||||
pub(in crate::api) cbPinAuth: u32,
|
||||
/// Pin Auth data
|
||||
pub(in crate::api) pbPinAuth: *const u8,
|
||||
|
||||
/// HMAC Salt Extension (Optional)
|
||||
pub(in crate::api) pHmacSaltExtension: *const WEBAUTHN_CTAPCBOR_HMAC_SALT_EXTENSION,
|
||||
|
||||
/// PRF Extension / HMAC secret salt values size
|
||||
pub(in crate::api) cbHmacSecretSaltValues: u32,
|
||||
/// PRF Extension / HMAC secret salt values data
|
||||
pub(in crate::api) pbHmacSecretSaltValues: *const u8,
|
||||
|
||||
/// Pin protocol
|
||||
pub(in crate::api) dwPinProtocol: u32,
|
||||
|
||||
/// "credBlob": true extension
|
||||
pub(in crate::api) lCredBlobExt: i32,
|
||||
|
||||
/// "largeBlobKey": true extension
|
||||
pub(in crate::api) lLargeBlobKeyExt: i32,
|
||||
|
||||
/// "largeBlob" extension operation
|
||||
pub(in crate::api) dwCredLargeBlobOperation: u32,
|
||||
/// Large blob compressed size
|
||||
pub(in crate::api) cbCredLargeBlobCompressed: u32,
|
||||
/// Large blob compressed data
|
||||
pub(in crate::api) pbCredLargeBlobCompressed: *const u8,
|
||||
/// Large blob original size
|
||||
pub(in crate::api) dwCredLargeBlobOriginalSize: u32,
|
||||
|
||||
/// "json" extension size. Nonzero if present
|
||||
pub(in crate::api) cbJsonExt: u32,
|
||||
/// "json" extension data
|
||||
pub(in crate::api) pbJsonExt: *const u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub(in crate::api) struct WEBAUTHN_CTAPCBOR_HMAC_SALT_EXTENSION {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
pub(in crate::api) _dwVersion: u32,
|
||||
|
||||
/// Platform's key agreement public key
|
||||
pub(in crate::api) _pKeyAgreement: *const WEBAUTHN_CTAPCBOR_ECC_PUBLIC_KEY,
|
||||
|
||||
/// Encrypted salt size
|
||||
pub(in crate::api) _cbEncryptedSalt: u32,
|
||||
/// Encrypted salt data
|
||||
pub(in crate::api) _pbEncryptedSalt: *const u8,
|
||||
|
||||
/// Salt authentication size
|
||||
pub(in crate::api) _cbSaltAuth: u32,
|
||||
/// Salt authentication data
|
||||
pub(in crate::api) _pbSaltAuth: *const u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(in crate::api) struct WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST<'a> {
|
||||
/// Version of this structure, to allow for modifications in the future.
|
||||
pub(in crate::api) dwVersion: u32,
|
||||
/// Input RP ID size (raw UTF-8 bytes before conversion)
|
||||
pub(in crate::api) cbRpId: u32,
|
||||
/// Input RP ID data (bytes hashed in Authenticator Data)
|
||||
pub(in crate::api) pbRpId: *const u8,
|
||||
/// Client Data Hash size
|
||||
pub(in crate::api) cbClientDataHash: u32,
|
||||
/// Client Data Hash data
|
||||
pub(in crate::api) pbClientDataHash: *const u8,
|
||||
/// RP Information
|
||||
pub(in crate::api) pRpInformation: *const WEBAUTHN_RP_ENTITY_INFORMATION,
|
||||
/// User Information
|
||||
pub(in crate::api) pUserInformation: *const WEBAUTHN_USER_ENTITY_INFORMATION,
|
||||
/// Crypto Parameters
|
||||
pub(in crate::api) WebAuthNCredentialParameters: WEBAUTHN_COSE_CREDENTIAL_PARAMETERS,
|
||||
/// Credentials used for exclusion
|
||||
pub(in crate::api) CredentialList: WEBAUTHN_CREDENTIAL_LIST,
|
||||
/// CBOR extensions map size
|
||||
pub(in crate::api) cbCborExtensionsMap: u32,
|
||||
/// CBOR extensions map data
|
||||
pub(in crate::api) pbCborExtensionsMap: *const u8,
|
||||
/// Authenticator Options (Optional)
|
||||
pub(in crate::api) pAuthenticatorOptions: Option<&'a WEBAUTHN_CTAPCBOR_AUTHENTICATOR_OPTIONS>,
|
||||
|
||||
// Pin Auth (Optional)
|
||||
/// Indicates zero length PinAuth is included in the request
|
||||
pub(in crate::api) fEmptyPinAuth: BOOL,
|
||||
/// Pin Auth size
|
||||
pub(in crate::api) cbPinAuth: u32,
|
||||
/// Pin Auth data
|
||||
pub(in crate::api) pbPinAuth: *const u8,
|
||||
|
||||
/// "hmac-secret": true extension
|
||||
pub(in crate::api) lHmacSecretExt: i32,
|
||||
|
||||
/// "hmac-secret-mc" extension
|
||||
pub(in crate::api) pHmacSecretMcExtension: *const WEBAUTHN_CTAPCBOR_HMAC_SALT_EXTENSION,
|
||||
|
||||
/// "prf" extension
|
||||
pub(in crate::api) lPrfExt: i32,
|
||||
/// HMAC secret salt values size
|
||||
pub(in crate::api) cbHmacSecretSaltValues: u32,
|
||||
/// HMAC secret salt values data
|
||||
pub(in crate::api) pbHmacSecretSaltValues: *const u8,
|
||||
|
||||
/// "credProtect" extension. Nonzero if present
|
||||
pub(in crate::api) dwCredProtect: Option<NonZeroU32>,
|
||||
|
||||
/// Nonzero if present
|
||||
pub(in crate::api) dwPinProtocol: Option<NonZeroU32>,
|
||||
|
||||
/// Nonzero if present
|
||||
pub(in crate::api) dwEnterpriseAttestation: Option<NonZeroU32>,
|
||||
|
||||
/// "credBlob" extension. Nonzero if present
|
||||
pub(in crate::api) cbCredBlobExt: Option<NonZeroU32>,
|
||||
/// "credBlob" extension data
|
||||
pub(in crate::api) pbCredBlobExt: *const u8,
|
||||
|
||||
/// "largeBlobKey": true extension
|
||||
pub(in crate::api) lLargeBlobKeyExt: i32,
|
||||
|
||||
/// "largeBlob": extension
|
||||
pub(in crate::api) dwLargeBlobSupport: u32,
|
||||
|
||||
/// "minPinLength": true extension
|
||||
pub(in crate::api) lMinPinLengthExt: i32,
|
||||
|
||||
/// "json" extension. Nonzero if present
|
||||
pub(in crate::api) cbJsonExt: u32,
|
||||
/// "json" extension data
|
||||
pub(in crate::api) pbJsonExt: *const u8,
|
||||
}
|
||||
|
||||
/// Used when adding a Windows plugin authenticator (stable API).
|
||||
/// Header File Name: _WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS
|
||||
/// Header File Usage: WebAuthNPluginAddAuthenticator()
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(in crate::api) struct WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS {
|
||||
/// Authenticator Name
|
||||
pub(in crate::api) pwszAuthenticatorName: *const u16,
|
||||
|
||||
/// Plugin COM ClsId
|
||||
pub(in crate::api) rclsid: *const GUID,
|
||||
|
||||
/// Plugin RPID
|
||||
///
|
||||
/// Required for a nested WebAuthN call originating from a plugin.
|
||||
pub(in crate::api) pwszPluginRpId: *const u16,
|
||||
|
||||
/// Plugin Authenticator Logo for the Light themes. base64-encoded SVG 1.1
|
||||
///
|
||||
/// The data should be encoded as `UTF16(BASE64(UTF8(svg_text)))`.
|
||||
pub(in crate::api) pwszLightThemeLogoSvg: *const u16,
|
||||
|
||||
/// Plugin Authenticator Logo for the Dark themes. base64-encoded SVG 1.1
|
||||
///
|
||||
/// The data should be encoded as `UTF16(BASE64(UTF8(svg_text)))`.
|
||||
pub(in crate::api) pwszDarkThemeLogoSvg: *const u16,
|
||||
|
||||
/// CTAP CBOR-encoded authenticatorGetInfo response (size)
|
||||
pub(in crate::api) cbAuthenticatorInfo: u32,
|
||||
/// CTAP CBOR-encoded authenticatorGetInfo output
|
||||
pub(in crate::api) pbAuthenticatorInfo: *const u8,
|
||||
|
||||
/// Count of supported RP IDs
|
||||
pub(in crate::api) cSupportedRpIds: u32,
|
||||
/// List of supported RP IDs (Relying Party IDs).
|
||||
///
|
||||
/// Should be null if all RPs are supported.
|
||||
pub(in crate::api) pbSupportedRpIds: *const *const u16,
|
||||
}
|
||||
|
||||
/// Used as a response type when adding a Windows plugin authenticator.
|
||||
/// Header File Name: _WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE
|
||||
/// Header File Usage: WebAuthNPluginAddAuthenticator()
|
||||
/// WebAuthNPluginFreeAddAuthenticatorResponse()
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(in crate::api) struct WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE {
|
||||
/// Size in bytes of the public key pointed to by `pbOpSignPubKey`.
|
||||
pub(in crate::api) cbOpSignPubKey: u32,
|
||||
/// Pointer to a [BCRYPT_KEY_BLOB](windows::Win32::Security::Cryptography::BCRYPT_KEY_BLOB).
|
||||
pub(in crate::api) pbOpSignPubKey: *mut u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub(in crate::api) struct WEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST {
|
||||
pub(in crate::api) transactionId: GUID,
|
||||
pub(in crate::api) cbRequestSignature: u32,
|
||||
pub(in crate::api) pbRequestSignature: *const u8,
|
||||
}
|
||||
|
||||
/// Represents a credential.
|
||||
/// Header File Name: _WEBAUTHN_PLUGIN_CREDENTIAL_DETAILS
|
||||
/// Header File Usage: WebAuthNPluginAuthenticatorAddCredentials, etc.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(in crate::api) struct WEBAUTHN_PLUGIN_CREDENTIAL_DETAILS {
|
||||
/// Credential Identifier bytes (size)
|
||||
pub(in crate::api) credential_id_byte_count: u32,
|
||||
/// Credential Identifier bytes (data, required)
|
||||
pub(in crate::api) credential_id_pointer: *const u8,
|
||||
/// Identifier for the RP (required)
|
||||
pub(in crate::api) rpid: *const u16,
|
||||
/// Friendly name of the Relying Party (required)
|
||||
pub(in crate::api) rp_friendly_name: *const u16,
|
||||
/// User Identifier bytes (size)
|
||||
pub(in crate::api) user_id_byte_count: u32,
|
||||
/// User Identifier bytes (data, required)
|
||||
pub(in crate::api) user_id_pointer: *const u8,
|
||||
/// Detailed account name (e.g., "john.p.smith@example.com")
|
||||
pub(in crate::api) user_name: *const u16,
|
||||
/// Friendly name for the user account (e.g., "John P. Smith")
|
||||
pub(in crate::api) user_display_name: *const u16,
|
||||
}
|
||||
|
||||
/// Used when creating and asserting credentials.
|
||||
/// Header File Name: _WEBAUTHN_PLUGIN_OPERATION_REQUEST
|
||||
/// Header File Usage: MakeCredential()
|
||||
/// GetAssertion()
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(in crate::api) struct WEBAUTHN_PLUGIN_OPERATION_REQUEST {
|
||||
/// Window handle to client that requesting a WebAuthn credential.
|
||||
pub(in crate::api) hWnd: HWND,
|
||||
pub(in crate::api) transactionId: GUID,
|
||||
pub(in crate::api) cbRequestSignature: u32,
|
||||
/// Signature over request made with the signing key created during authenticator registration.
|
||||
pub(in crate::api) pbRequestSignature: *mut u8,
|
||||
pub(in crate::api) requestType: WEBAUTHN_PLUGIN_REQUEST_TYPE,
|
||||
pub(in crate::api) cbEncodedRequest: u32,
|
||||
pub(in crate::api) pbEncodedRequest: *const u8,
|
||||
}
|
||||
|
||||
/// Plugin request type enum as defined in the IDL
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(in crate::api) enum WEBAUTHN_PLUGIN_REQUEST_TYPE {
|
||||
// This is being used to check the value that Windows gives us, but it isn't
|
||||
// ever constructed by our library.
|
||||
#[allow(unused)]
|
||||
CTAP2_CBOR = 0x01,
|
||||
}
|
||||
|
||||
/// Used as a response when creating and asserting credentials.
|
||||
/// Header File Name: _WEBAUTHN_PLUGIN_OPERATION_RESPONSE
|
||||
/// Header File Usage: MakeCredential()
|
||||
/// GetAssertion()
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(in crate::api) struct WEBAUTHN_PLUGIN_OPERATION_RESPONSE {
|
||||
pub(in crate::api) cbEncodedResponse: u32,
|
||||
pub(in crate::api) pbEncodedResponse: *mut u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub(in crate::api) struct WEBAUTHN_PLUGIN_USER_VERIFICATION_REQUEST {
|
||||
/// Windows handle of the top-level window displayed by the plugin and
|
||||
/// currently is in foreground as part of the ongoing WebAuthn operation.
|
||||
pub(in crate::api) hwnd: HWND,
|
||||
|
||||
/// The WebAuthn transaction id from the WEBAUTHN_PLUGIN_OPERATION_REQUEST
|
||||
pub(in crate::api) rguidTransactionId: *const GUID,
|
||||
|
||||
/// The username attached to the credential that is in use for this WebAuthn
|
||||
/// operation.
|
||||
pub(in crate::api) pwszUsername: *const u16,
|
||||
|
||||
/// A text hint displayed on the Windows Hello prompt.
|
||||
pub(in crate::api) pwszDisplayHint: *const u16,
|
||||
}
|
||||
|
||||
webauthn_call!("WebAuthNDecodeGetAssertionRequest" as
|
||||
/// Decodes a CTAP GetAssertion request.
|
||||
///
|
||||
/// On success, a [WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST] will be written to
|
||||
/// `ppGetAssertionRequest`, which must be freed by a call to
|
||||
/// [webauthn_free_decoded_get_assertion_request].
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pbEncoded`: a COM-allocated buffer pointing to a CTAP CBOR get assertion request.
|
||||
/// - `ppGetAssertionRequest`: An indirect pointer to a [WEBAUTHN_CTAPCBOR_GET_ASSERTION_REQUEST].
|
||||
///
|
||||
/// # Safety
|
||||
/// - `pbEncoded` must have been allocated by Windows COM.
|
||||
/// - `pbEncoded` must be non-null and have the length specified in cbEncoded.
|
||||
fn webauthn_decode_get_assertion_request(
|
||||
cbEncoded: u32,
|
||||
pbEncoded: *const u8,
|
||||
ppGetAssertionRequest: *mut *mut WEBAUTHN_CTAPCBOR_GET_ASSERTION_REQUEST
|
||||
) -> HRESULT);
|
||||
|
||||
webauthn_call!("WebAuthNDecodeMakeCredentialRequest" as
|
||||
/// Decodes a CTAP CBOR `authenticatorMakeCredential` request.
|
||||
///
|
||||
/// On success, a [WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST] will be written to
|
||||
/// `ppMakeCredentialRequest`, which must be freed by a call to
|
||||
/// [webauthn_free_decoded_make_credential_request].
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pbEncoded`: a COM-allocated buffer pointing to a CTAP CBOR make credential request.
|
||||
/// - `ppMakeCredentialRequest`: An indirect pointer to a [WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST].
|
||||
///
|
||||
/// # Safety
|
||||
/// - `pbEncoded` must have been allocated by Windows COM.
|
||||
/// - `pbEncoded` must be non-null and have the length specified in cbEncoded.
|
||||
fn webauthn_decode_make_credential_request(
|
||||
cbEncoded: u32,
|
||||
pbEncoded: *const u8,
|
||||
ppMakeCredentialRequest: *mut *mut WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST
|
||||
) -> HRESULT);
|
||||
|
||||
webauthn_call!("WebAuthNEncodeMakeCredentialResponse" as
|
||||
/// Encode a credential attestation response to a COM-allocated byte buffer
|
||||
/// containing a CTAP CBOR `authenticatorMakeCredential` response structure.
|
||||
///
|
||||
/// Returns [S_OK](windows::Win32::Foundation::S_OK) on success.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pCredentialAttestation`: A pointer to [WEBAUTHN_CREDENTIAL_ATTESTATION] to encode.
|
||||
/// - `pcbResp`: A pointer to a u32, which will be filled with the length of the response buffer.
|
||||
/// - `ppbResponse`: An indirect pointer to a byte buffer, which will be written to on succces.
|
||||
fn webauthn_encode_make_credential_response(
|
||||
pCredentialAttestation: *const WEBAUTHN_CREDENTIAL_ATTESTATION,
|
||||
pcbResp: *mut u32,
|
||||
ppbResponse: *mut *mut u8
|
||||
) -> HRESULT);
|
||||
|
||||
webauthn_call!("WebAuthNFreeDecodedGetAssertionRequest" as
|
||||
/// Frees a decoded get assertion request from [webauthn_free_decoded_get_assertion_request].
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pGetAssertionRequest`: An pointer to a [WEBAUTHN_CTAPCBOR_GET_ASSERTION_REQUEST] to be freed.
|
||||
fn webauthn_free_decoded_get_assertion_request(
|
||||
pGetAssertionRequest: *mut WEBAUTHN_CTAPCBOR_GET_ASSERTION_REQUEST
|
||||
) -> ());
|
||||
|
||||
webauthn_call!("WebAuthNFreeDecodedMakeCredentialRequest" as
|
||||
/// Frees a decoded make credential request from [webauthn_free_decoded_make_credential_request].
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pMakeCredentialRequest`: An pointer to a [WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST] to be freed.
|
||||
fn webauthn_free_decoded_make_credential_request(
|
||||
pMakeCredentialRequest: *mut WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST
|
||||
) -> ());
|
||||
|
||||
webauthn_call!("WebAuthNPluginAddAuthenticator" as
|
||||
/// Register authenticator info for a plugin COM server.
|
||||
///
|
||||
/// Returns [S_OK](windows::Win32::Foundation::S_OK) on success.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pPluginAddAuthenticatorOptions`: Details about the authenticator to set.
|
||||
/// - `ppPluginAddAuthenticatorResponse`:
|
||||
/// An indirect pointer to a [WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE], which will be written to on success.
|
||||
/// If the request succeeds, the data must be freed by a call to [webauthn_plugin_free_add_authenticator_response].
|
||||
fn webauthn_plugin_add_authenticator(
|
||||
pPluginAddAuthenticatorOptions: *const WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS,
|
||||
ppPluginAddAuthenticatorResponse: *mut *mut WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE
|
||||
) -> HRESULT);
|
||||
|
||||
webauthn_call!("WebAuthNPluginAuthenticatorAddCredentials" as
|
||||
/// Add metadata for a list of WebAuthn credentials to the autofill store for
|
||||
/// this plugin authenticator.
|
||||
///
|
||||
/// This will make the credentials available for discovery in Windows Hello
|
||||
/// WebAuthn autofill dialogs.
|
||||
///
|
||||
/// Returns [S_OK](windows::Win32::Foundation::S_OK) on success.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `rclsid`: The CLSID corresponding to this plugin's COM server.
|
||||
/// - `cCredentialDetails`: The number of credentials in the array pointed to by `pCredentialDetails`.
|
||||
/// - `pCredentialDetails`: An array of credential metadata.
|
||||
fn webauthn_plugin_authenticator_add_credentials(
|
||||
rclsid: *const GUID,
|
||||
cCredentialDetails: u32,
|
||||
pCredentialDetails: *const WEBAUTHN_PLUGIN_CREDENTIAL_DETAILS
|
||||
) -> HRESULT);
|
||||
|
||||
webauthn_call!("WebAuthNPluginAuthenticatorRemoveAllCredentials" as
|
||||
/// Removes metadata for all credentials currently stored in the autofill store
|
||||
/// for this plugin authenticator.
|
||||
///
|
||||
/// Returns [S_OK](windows::Win32::Foundation::S_OK) on success.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `rclsid`: The CLSID corresponding to this plugin's COM server.
|
||||
fn webauthn_plugin_authenticator_remove_all_credentials(rclsid: *const GUID) -> HRESULT);
|
||||
|
||||
webauthn_call!("WebAuthNPluginFreeAddAuthenticatorResponse" as
|
||||
/// Free memory from a [WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE].
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pPluginAddAuthenticatorResponse`: An pointer to a [WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE] to be freed.
|
||||
fn webauthn_plugin_free_add_authenticator_response(
|
||||
pPluginAddAuthenticatorResponse: *mut WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE
|
||||
) -> ());
|
||||
|
||||
webauthn_call!("WebAuthNPluginFreeUserVerificationResponse" as
|
||||
/// Free a user verification response received from a call to [webauthn_plugin_perform_user_verification].
|
||||
fn webauthn_plugin_free_user_verification_response(
|
||||
pbResponse: *mut u8
|
||||
) -> ());
|
||||
|
||||
webauthn_call!("WebAuthNPluginPerformUserVerification" as
|
||||
/// Request user verification for a WebAuthn operation.
|
||||
///
|
||||
/// The OS will prompt the user for verification, and if the user is
|
||||
/// successfully verified, will write a signature to `ppbResponse`, which must
|
||||
/// be freed by a call to [webauthn_plugin_free_user_verification_response].
|
||||
///
|
||||
/// The signature is over the SHA-256 hash of the original WebAuthn operation request buffer
|
||||
/// corresponding to `pPluginUserVerification.rguidTransactionId`. It can be
|
||||
/// verified using the user verification public key, which can be retrieved
|
||||
/// using
|
||||
/// [webauthn_plugin_get_user_verification_public_key][crate::plugin::crypto::webauthn_plugin_get_user_verification_public_key].
|
||||
///
|
||||
/// This request will block while the user interacts with the dialog.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pPluginUserVerification`: The user verification prompt and transaction context for the request.
|
||||
/// - `pcbResponse`: Length in bytes of the signature.
|
||||
/// - `ppbResponse`: The signature of the request.
|
||||
fn webauthn_plugin_perform_user_verification(
|
||||
pPluginUserVerification: *const WEBAUTHN_PLUGIN_USER_VERIFICATION_REQUEST,
|
||||
pcbResponse: *mut u32,
|
||||
ppbResponse: *mut *mut u8
|
||||
) -> HRESULT);
|
||||
|
||||
webauthn_call!("WebAuthNPluginGetUserVerificationPublicKey" as
|
||||
/// Retrieve the public key used to verify user verification responses from the OS.
|
||||
///
|
||||
/// Returns [S_OK](windows::Win32::Foundation::S_OK) on success.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `rclsid`: The CLSID corresponding to this plugin's COM server.
|
||||
/// - `pcbPublicKey`: A pointer to an unsigned integer, which will be filled in with the length of the buffer at `ppbPublicKey`.
|
||||
/// - `ppbPublicKey`: A pointer to a [BCRYPT_PUBLIC_KEY_BLOB], which will be written to on success.
|
||||
/// On success, this must be freed by a call to [webauthn_plugin_free_public_key_response].
|
||||
fn webauthn_plugin_get_user_verification_public_key(
|
||||
rclsid: *const GUID,
|
||||
pcbPublicKey: *mut u32,
|
||||
ppbPublicKey: *mut *mut BCRYPT_KEY_BLOB,
|
||||
) -> HRESULT); // Free using WebAuthNPluginFreePublicKeyResponse
|
||||
|
||||
webauthn_call!("WebAuthNPluginGetOperationSigningPublicKey" as
|
||||
/// Retrieve the public key used to verify plugin operation requests from the OS.
|
||||
///
|
||||
/// Returns [S_OK](windows::Win32::Foundation::S_OK) on success.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `rclsid`: The CLSID corresponding to this plugin's COM server.
|
||||
/// - `pcbOpSignPubKey`: A pointer to an unsigned integer, which will be filled in with the length of the buffer at `ppbOpSignPubKey`.
|
||||
/// - `ppbOpSignPubKey`: An indirect pointer to a [BCRYPT_PUBLIC_KEY_BLOB], which will be written to on success.
|
||||
/// On success, this must be freed by a call to [webauthn_plugin_free_public_key_response].
|
||||
fn webauthn_plugin_get_operation_signing_public_key(
|
||||
rclsid: *const GUID,
|
||||
pcbOpSignPubKey: *mut u32,
|
||||
ppbOpSignPubKey: *mut *mut BCRYPT_KEY_BLOB
|
||||
) -> HRESULT); // Free using WebAuthNPluginFreePublicKeyResponse
|
||||
|
||||
webauthn_call!("WebAuthNPluginFreePublicKeyResponse" as
|
||||
/// Free public key memory retrieved from the OS.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `pbOpSignPubKey`: A pointer to a [BCRYPT_KEY_BLOB] retrieved from a method in this library.
|
||||
fn webauthn_plugin_free_public_key_response(
|
||||
pbOpSignPubKey: *mut BCRYPT_KEY_BLOB
|
||||
) -> ());
|
||||
94
apps/desktop/desktop_native/win_webauthn/src/api/sys/util.rs
Normal file
94
apps/desktop/desktop_native/win_webauthn/src/api/sys/util.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use windows::{
|
||||
core::s,
|
||||
Win32::{
|
||||
Foundation::{FreeLibrary, HMODULE},
|
||||
System::LibraryLoader::{
|
||||
GetModuleHandleExA, LoadLibraryExA, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
GET_MODULE_HANDLE_EX_FLAG_PIN, LOAD_LIBRARY_SEARCH_SYSTEM32,
|
||||
},
|
||||
},
|
||||
};
|
||||
use windows_core::{PCSTR, PCWSTR};
|
||||
|
||||
use crate::{ErrorKind, WinWebAuthnError};
|
||||
|
||||
struct SafeModule(HMODULE);
|
||||
impl SafeModule {
|
||||
unsafe fn new(mut module: HMODULE) -> windows::core::Result<Self> {
|
||||
unsafe {
|
||||
// Pin the module so that it cannot be unloaded.
|
||||
GetModuleHandleExA(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
|
||||
PCSTR::from_raw(module.0.cast()),
|
||||
&mut module,
|
||||
)?;
|
||||
}
|
||||
Ok(Self(module))
|
||||
}
|
||||
}
|
||||
static WEBAUTHN_LIB: OnceLock<windows::core::Result<SafeModule>> = OnceLock::new();
|
||||
|
||||
unsafe impl Send for SafeModule {}
|
||||
unsafe impl Sync for SafeModule {}
|
||||
|
||||
/// Defines a Rust function to call a webauthn.dll function over FFI based on
|
||||
/// the name of the function. Documentation comments will be captured, and the
|
||||
/// return type will be wrapped in a WinWebAuthnError that will be returned if
|
||||
/// the function cannot be loaded from webauthn.dll.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use crate::api::sys::util::webauthn_call;
|
||||
///
|
||||
/// webauthn_call!("WebAuthNFreeDecodedMakeCredentialRequest" as
|
||||
/// /// Frees a decoded make credential request from [webauthn_free_decoded_make_credential_request].
|
||||
/// ///
|
||||
/// /// # Arguments
|
||||
/// /// - `pMakeCredentialRequest`: An pointer to a [WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST] to be freed.
|
||||
/// fn webauthn_free_decoded_make_credential_request(
|
||||
/// pMakeCredentialRequest: *mut WEBAUTHN_CTAPCBOR_MAKE_CREDENTIAL_REQUEST
|
||||
/// ) -> ());
|
||||
/// ```
|
||||
macro_rules! webauthn_call {
|
||||
($symbol:literal as $(#[$attr:meta])* fn $fn_name:ident($($arg:ident: $arg_type:ty),+ $(,)?) -> $result_type:ty) => (
|
||||
$(#[$attr])*
|
||||
pub(in crate::api) unsafe fn $fn_name($($arg: $arg_type),*) -> Result<$result_type, crate::WinWebAuthnError> {
|
||||
let library = crate::api::sys::util::load_webauthn_lib()?;
|
||||
let response = unsafe {
|
||||
let address = windows::Win32::System::LibraryLoader::GetProcAddress(*library, windows::core::s!($symbol)).ok_or(
|
||||
crate::WinWebAuthnError::new(
|
||||
crate::ErrorKind::DllLoad,
|
||||
&format!(
|
||||
"Failed to load function {}",
|
||||
$symbol
|
||||
),
|
||||
),
|
||||
)?;
|
||||
|
||||
let function: unsafe extern "C" fn(
|
||||
$($arg: $arg_type),*
|
||||
) -> $result_type = std::mem::transmute_copy(&address);
|
||||
function($($arg),*)
|
||||
};
|
||||
Ok(response)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) use webauthn_call;
|
||||
|
||||
pub(super) fn load_webauthn_lib() -> Result<&'static HMODULE, WinWebAuthnError> {
|
||||
WEBAUTHN_LIB
|
||||
.get_or_init(|| unsafe {
|
||||
LoadLibraryExA(s!("webauthn.dll"), None, LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||
.and_then(|library| SafeModule::new(library))
|
||||
})
|
||||
.as_ref()
|
||||
.map(|module| &module.0)
|
||||
.map_err(|err| {
|
||||
WinWebAuthnError::with_cause(ErrorKind::DllLoad, "Failed to load webauthn.dll", err)
|
||||
})
|
||||
}
|
||||
85
apps/desktop/desktop_native/win_webauthn/src/lib.rs
Normal file
85
apps/desktop/desktop_native/win_webauthn/src/lib.rs
Normal file
@ -0,0 +1,85 @@
|
||||
//! A Rust wrapper around the webauthn.dll API.
|
||||
//!
|
||||
//! The root module contains common types for WebAuthn clients and plugins.
|
||||
//!
|
||||
//! The [plugin] module has types useful for implementing a Windows passkey
|
||||
//! plugin authenticator.
|
||||
#![cfg(target_os = "windows")]
|
||||
// TODO: Temporarily allow unused code while scaffolding. Remove once PR set is finished.
|
||||
#![expect(unused)]
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) mod api;
|
||||
|
||||
use std::{error::Error, fmt::Display};
|
||||
|
||||
/// Errors that may be returned when interacting with this library.
|
||||
#[derive(Debug)]
|
||||
pub struct WinWebAuthnError {
|
||||
kind: ErrorKind,
|
||||
description: Option<String>,
|
||||
cause: Option<Box<dyn std::error::Error>>,
|
||||
}
|
||||
|
||||
impl WinWebAuthnError {
|
||||
pub(crate) fn new(kind: ErrorKind, description: &str) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
description: Some(description.to_string()),
|
||||
cause: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_cause<E: std::error::Error + 'static>(
|
||||
kind: ErrorKind,
|
||||
description: &str,
|
||||
cause: E,
|
||||
) -> Self {
|
||||
let cause: Box<dyn std::error::Error> = Box::new(cause);
|
||||
Self {
|
||||
kind,
|
||||
description: Some(description.to_string()),
|
||||
cause: Some(cause),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ErrorKind {
|
||||
/// There was an error loading the webauthn.dll library.
|
||||
DllLoad,
|
||||
|
||||
/// There was an error parsing or serializing data.
|
||||
Serialization,
|
||||
|
||||
/// An invalid argument was passed.
|
||||
InvalidArguments,
|
||||
|
||||
/// An unknown error occurred.
|
||||
Other,
|
||||
|
||||
/// An internal library error occurred.
|
||||
WindowsInternal,
|
||||
}
|
||||
|
||||
impl Display for WinWebAuthnError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let msg = match self.kind {
|
||||
ErrorKind::Serialization => "Failed to serialize data",
|
||||
ErrorKind::DllLoad => "Failed to load function from DLL",
|
||||
ErrorKind::InvalidArguments => "Invalid arguments passed to function",
|
||||
ErrorKind::Other => "An error occurred",
|
||||
ErrorKind::WindowsInternal => "A Windows error occurred",
|
||||
};
|
||||
f.write_str(msg)?;
|
||||
if let Some(d) = &self.description {
|
||||
write!(f, ": {d}")?;
|
||||
}
|
||||
if let Some(e) = &self.cause {
|
||||
write!(f, ". Caused by: {e}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for WinWebAuthnError {}
|
||||
Loading…
Reference in New Issue
Block a user