From 3032f4f523dce64491e819e33ea7d66158506d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85berg?= Date: Thu, 14 Aug 2025 21:34:54 +0200 Subject: [PATCH] Implement EXPERIMENTAL2 --- .../src/com_provider.rs | 104 +++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/com_provider.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/com_provider.rs index 9c33bc689f4..11b7b26b798 100644 --- a/apps/desktop/desktop_native/windows_plugin_authenticator/src/com_provider.rs +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/com_provider.rs @@ -7,6 +7,13 @@ use crate::make_credential::experimental_plugin_make_credential; use crate::util::debug_log; use crate::webauthn::WEBAUTHN_CREDENTIAL_LIST; +/// Plugin request type enum as defined in the IDL +#[repr(u32)] +#[derive(Debug, Copy, Clone)] +pub enum WebAuthnPluginRequestType { + CTAP2_CBOR = 0x01, +} + /// Plugin lock status enum as defined in the IDL #[repr(u32)] #[derive(Debug, Copy, Clone)] @@ -30,6 +37,22 @@ pub struct ExperimentalWebAuthnPluginOperationRequest { pub encoded_request_pointer: *mut u8, } +/// Used when creating and asserting credentials with EXPERIMENTAL2 interface. +/// Header File Name: _EXPERIMENTAL2_WEBAUTHN_PLUGIN_OPERATION_REQUEST +/// Header File Usage: EXPERIMENTAL_MakeCredential() +/// EXPERIMENTAL_GetAssertion() +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Experimental2WebAuthnPluginOperationRequest { + pub window_handle: windows::Win32::Foundation::HWND, + pub transaction_id: windows_core::GUID, + pub request_signature_byte_count: u32, + pub request_signature_pointer: *mut u8, + pub request_type: WebAuthnPluginRequestType, + pub encoded_request_byte_count: u32, + pub encoded_request_pointer: *mut u8, +} + /// Used as a response when creating and asserting credentials. /// Header File Name: _EXPERIMENTAL_WEBAUTHN_PLUGIN_OPERATION_RESPONSE @@ -75,6 +98,28 @@ pub unsafe trait EXPERIMENTAL_IPluginAuthenticator: windows_core::IUnknown { ) -> HRESULT; } +#[interface("d26bcf6f-b54c-43ff-9f06-d5bf148625f7")] +pub unsafe trait EXPERIMENTAL2_IPluginAuthenticator: windows_core::IUnknown { + fn EXPERIMENTAL_MakeCredential( + &self, + request: *const Experimental2WebAuthnPluginOperationRequest, + response: *mut *mut ExperimentalWebAuthnPluginOperationResponse, + ) -> HRESULT; + fn EXPERIMENTAL_GetAssertion( + &self, + request: *const Experimental2WebAuthnPluginOperationRequest, + response: *mut *mut ExperimentalWebAuthnPluginOperationResponse, + ) -> HRESULT; + fn EXPERIMENTAL_CancelOperation( + &self, + request: *const ExperimentalWebAuthnPluginCancelOperationRequest, + ) -> HRESULT; + fn EXPERIMENTAL_GetLockStatus( + &self, + lock_status: *mut PluginLockStatus, + ) -> HRESULT; +} + pub unsafe fn parse_credential_list(credential_list: &WEBAUTHN_CREDENTIAL_LIST) -> Vec> { let mut allowed_credentials = Vec::new(); @@ -129,7 +174,7 @@ pub unsafe fn parse_credential_list(credential_list: &WEBAUTHN_CREDENTIAL_LIST) allowed_credentials } -#[implement(EXPERIMENTAL_IPluginAuthenticator)] +#[implement(EXPERIMENTAL_IPluginAuthenticator, EXPERIMENTAL2_IPluginAuthenticator)] pub struct PluginAuthenticatorComObject; #[implement(IClassFactory)] @@ -168,7 +213,62 @@ impl EXPERIMENTAL_IPluginAuthenticator_Impl for PluginAuthenticatorComObject_Imp if lock_status.is_null() { return HRESULT(-2147024809); // E_INVALIDARG } - // For now, always return unlocked + *lock_status = PluginLockStatus::PluginUnlocked; + HRESULT(0) + } +} + +impl EXPERIMENTAL2_IPluginAuthenticator_Impl for PluginAuthenticatorComObject_Impl { + unsafe fn EXPERIMENTAL_MakeCredential( + &self, + request: *const Experimental2WebAuthnPluginOperationRequest, + response: *mut *mut ExperimentalWebAuthnPluginOperationResponse, + ) -> HRESULT { + debug_log("EXPERIMENTAL2_MakeCredential() called"); + let legacy_request = ExperimentalWebAuthnPluginOperationRequest { + window_handle: (*request).window_handle, + transaction_id: (*request).transaction_id, + request_signature_byte_count: (*request).request_signature_byte_count, + request_signature_pointer: (*request).request_signature_pointer, + encoded_request_byte_count: (*request).encoded_request_byte_count, + encoded_request_pointer: (*request).encoded_request_pointer, + }; + experimental_plugin_make_credential(&legacy_request, response) + } + + unsafe fn EXPERIMENTAL_GetAssertion( + &self, + request: *const Experimental2WebAuthnPluginOperationRequest, + response: *mut *mut ExperimentalWebAuthnPluginOperationResponse, + ) -> HRESULT { + debug_log("EXPERIMENTAL2_GetAssertion() called"); + let legacy_request = ExperimentalWebAuthnPluginOperationRequest { + window_handle: (*request).window_handle, + transaction_id: (*request).transaction_id, + request_signature_byte_count: (*request).request_signature_byte_count, + request_signature_pointer: (*request).request_signature_pointer, + encoded_request_byte_count: (*request).encoded_request_byte_count, + encoded_request_pointer: (*request).encoded_request_pointer, + }; + experimental_plugin_get_assertion(&legacy_request, response) + } + + unsafe fn EXPERIMENTAL_CancelOperation( + &self, + _request: *const ExperimentalWebAuthnPluginCancelOperationRequest, + ) -> HRESULT { + debug_log("EXPERIMENTAL2_CancelOperation() called"); + HRESULT(0) + } + + unsafe fn EXPERIMENTAL_GetLockStatus( + &self, + lock_status: *mut PluginLockStatus, + ) -> HRESULT { + debug_log("EXPERIMENTAL2_GetLockStatus() called"); + if lock_status.is_null() { + return HRESULT(-2147024809); // E_INVALIDARG + } *lock_status = PluginLockStatus::PluginUnlocked; HRESULT(0) }