1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-21 11:54:02 +00:00

Add documentation to webauthn.dll functions

This commit is contained in:
Isaiah Inuwa
2026-02-19 07:51:46 -06:00
parent eaa955a87b
commit 07b551fd39
2 changed files with 180 additions and 25 deletions

View File

@@ -20,21 +20,51 @@ use windows::{
use crate::{util::webauthn_call, ErrorKind, WinWebAuthnError};
webauthn_call!("WebAuthNPluginGetUserVerificationPublicKey" as fn webauthn_plugin_get_user_verification_public_key(
rclsid: *const GUID,
pcbPublicKey: *mut u32,
ppbPublicKey: *mut *mut u8) -> HRESULT); // Free using WebAuthNPluginFreePublicKeyResponse
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 u8
) -> HRESULT); // Free using WebAuthNPluginFreePublicKeyResponse
webauthn_call!("WebAuthNPluginGetOperationSigningPublicKey" as fn webauthn_plugin_get_operation_signing_public_key(
rclsid: *const GUID,
pcbOpSignPubKey: *mut u32,
ppbOpSignPubKey: *mut *mut u8
) -> HRESULT); // Free using WebAuthNPluginFreePublicKeyResponse
webauthn_call!("WebAuthNPluginGetOperationSigningPublicKey" as
/// Retrieve the public key used to verify plugin operation reqeusts 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 u8
) -> HRESULT); // Free using WebAuthNPluginFreePublicKeyResponse
webauthn_call!("WebAuthNPluginFreePublicKeyResponse" as fn webauthn_plugin_free_public_key_response(
webauthn_call!("WebAuthNPluginFreePublicKeyResponse" as
/// Free public key memory retrieved from the OS.
///
/// # Arguments
/// - `pbOpSignPubKey`: A pointer to a [BCRYPT_PUBLIC_KEY_BLOB] retrieved from a method in this library.
fn webauthn_plugin_free_public_key_response(
pbOpSignPubKey: *mut u8
) -> ());
/// Retrieve the public key used to verify plugin operation reqeusts from the OS.
///
/// # Arguments
/// - `clsid`: The CLSID corresponding to this plugin's COM server.
pub(super) fn get_operation_signing_public_key(
clsid: &GUID,
) -> Result<SigningKey, WinWebAuthnError> {
@@ -66,6 +96,10 @@ pub(super) fn get_operation_signing_public_key(
}
}
/// Retrieve the public key used to verify user verification responses from the OS.
///
/// # Arguments
/// - `clsid`: The CLSID corresponding to this plugin's COM server.
pub(super) fn get_user_verification_public_key(
clsid: &GUID,
) -> Result<SigningKey, WinWebAuthnError> {
@@ -95,6 +129,7 @@ pub(super) fn get_user_verification_public_key(
}
}
/// Verify a public key signature over a hash using Windows Crypto APIs.
fn verify_signature(
public_key: &SigningKey,
hash: &[u8],
@@ -128,6 +163,18 @@ fn verify_signature(
if public_key.len() < size_of::<BCRYPT_KEY_BLOB>() {
return Err(windows::core::Error::from_hresult(E_INVALIDARG));
}
// BCRYPT_KEY_BLOB is a base structure for all types of keys used in the BCRYPT API.
// Cf. https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_key_blob.
//
// The first field is a "magic" field that denotes the algorithm (RSA,
// P-256, P-384, etc.) and subtype (public, private; RSA also has a
// "full private" key that includes the key exponents and coefficients).
//
// The exact key types which the OS can return from webauthn.dll
// operations is not documented, but we have observed at least RSA
// public keys being used. For forward compatibility, we'll implement
// RSA, P-256, P-384 and P-512.
let key_blob: &BCRYPT_KEY_BLOB = &*public_key.as_ptr().cast();
tracing::debug!(" got key magic: {}", key_blob.Magic);
let (padding_info, cng_flags) = if key_blob.Magic == BCRYPT_RSAPUBLIC_MAGIC.0 {
@@ -156,6 +203,7 @@ fn verify_signature(
}
}
/// Calculate a SHA-256 hash over some data.
pub(super) fn hash_sha256(data: &[u8]) -> Result<Vec<u8>, windows::core::Error> {
unsafe {
// Hash data
@@ -256,7 +304,9 @@ impl Drop for BcryptHash {
/// Signing key for an operation request or user verification response buffer.
pub struct SigningKey {
/// Length of buffer
cbPublicKey: u32,
/// Pointer to a [BCRYPT_KEY_BLOB]
pbPublicKey: NonNull<u8>,
}
@@ -272,6 +322,7 @@ impl SigningKey {
})
}
}
impl Drop for SigningKey {
fn drop(&mut self) {
unsafe {
@@ -279,6 +330,7 @@ impl Drop for SigningKey {
}
}
}
impl AsRef<[u8]> for SigningKey {
fn as_ref(&self) -> &[u8] {
// SAFETY: We only support platforms where usize >= 32-bts

View File

@@ -166,7 +166,9 @@ impl PluginAddAuthenticatorOptions {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub(super) struct WebAuthnPluginAddAuthenticatorResponse {
/// Size in bytes of the public key pointed to by `pbOpSignPubKey`.
cbOpSignPubKey: u32,
/// Pointer to a [BCRYPT_KEY_BLOB](windows::Win32::Security::Cryptography::BCRYPT_KEY_BLOB).
pbOpSignPubKey: *mut u8,
}
@@ -217,14 +219,27 @@ impl Drop for PluginAddAuthenticatorResponse {
}
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!("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(
pPluginAddAuthenticatorOptions: *mut WebAuthnPluginAddAuthenticatorResponse
pPluginAddAuthenticatorResponse: *mut WebAuthnPluginAddAuthenticatorResponse
) -> ());
// Credential syncing types
@@ -271,15 +286,34 @@ pub struct PluginCredentialDetails {
pub user_display_name: String,
}
webauthn_call!("WebAuthNPluginAuthenticatorAddCredentials" as fn webauthn_plugin_authenticator_add_credentials(
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 fn webauthn_plugin_authenticator_remove_all_credentials(
rclsid: *const GUID
) -> 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);
#[repr(C)]
#[derive(Debug)]
@@ -323,13 +357,34 @@ pub struct PluginUserVerificationResponse {
pub signature: Vec<u8>,
}
webauthn_call!("WebAuthNPluginPerformUserVerification" as fn webauthn_plugin_perform_user_verification(
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!("WebAuthNPluginFreeUserVerificationResponse" as fn webauthn_plugin_free_user_verification_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
) -> ());
@@ -594,13 +649,32 @@ impl Drop for PluginMakeCredentialRequest {
}
// Windows API function signatures for decoding make credential requests
webauthn_call!("WebAuthNDecodeMakeCredentialRequest" as fn webauthn_decode_make_credential_request(
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!("WebAuthNFreeDecodedMakeCredentialRequest" as fn webauthn_free_decoded_make_credential_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
) -> ());
@@ -823,10 +897,20 @@ impl TryFrom<PluginMakeCredentialResponse> for WEBAUTHN_CREDENTIAL_ATTESTATION {
}
}
webauthn_call!("WebAuthNEncodeMakeCredentialResponse" as fn webauthn_encode_make_credential_response(
cbEncoded: *const WEBAUTHN_CREDENTIAL_ATTESTATION,
pbEncoded: *mut u32,
response_bytes: *mut *mut u8
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);
// GetAssertion types
@@ -1044,13 +1128,32 @@ impl Drop for PluginGetAssertionRequest {
}
// Windows API function signatures for decoding get assertion requests
webauthn_call!("WebAuthNDecodeGetAssertionRequest" as fn webauthn_decode_get_assertion_request(
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!("WebAuthNFreeDecodedGetAssertionRequest" as fn webauthn_free_decoded_get_assertion_request(
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
) -> ());