From 24786a08df6e059c5f9f3e4e7fa7abde54e4247c Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Fri, 25 Apr 2025 14:42:11 -0400 Subject: [PATCH] [PM-20451] Refactor Windows PA Types (#14366) * PM-20451: Rename and organize Windows types * PM-20451: Add comments --- .../windows_plugin_authenticator/src/lib.rs | 167 +++--------------- .../src/pluginauthenticator.rs | 110 ++++++++++++ .../src/webauthn.rs | 29 +++ 3 files changed, 161 insertions(+), 145 deletions(-) create mode 100644 apps/desktop/desktop_native/windows_plugin_authenticator/src/pluginauthenticator.rs create mode 100644 apps/desktop/desktop_native/windows_plugin_authenticator/src/webauthn.rs diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/lib.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/lib.rs index 21257068bd0..cdea50aee99 100644 --- a/apps/desktop/desktop_native/windows_plugin_authenticator/src/lib.rs +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/lib.rs @@ -9,58 +9,14 @@ use windows::Win32::System::Com::*; use windows::Win32::System::LibraryLoader::*; use windows_core::*; +mod pluginauthenticator; +mod webauthn; + const AUTHENTICATOR_NAME: &str = "Bitwarden Desktop Authenticator"; //const AAGUID: &str = "d548826e-79b4-db40-a3d8-11116f7e8349"; const CLSID: &str = "0f7dc5d9-69ce-4652-8572-6877fd695062"; const RPID: &str = "bitwarden.com"; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct EXPERIMENTAL_WEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST { - pub transactionId: GUID, - pub cbRequestSignature: Dword, - pub pbRequestSignature: *mut byte, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct EXPERIMENTAL_WEBAUTHN_PLUGIN_OPERATION_REQUEST { - pub hWnd: HWND, - pub transactionId: GUID, - pub cbRequestSignature: Dword, - pub pbRequestSignature: *mut byte, - pub cbEncodedRequest: Dword, - pub pbEncodedRequest: *mut byte, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE { - pub cbOpSignPubKey: Dword, - pub pbOpSignPubKey: PByte, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct EXPERIMENTAL_WEBAUTHN_PLUGIN_OPERATION_RESPONSE { - pub cbEncodedResponse: Dword, - pub pbEncodedResponse: *mut byte, -} - -type Dword = u32; -type Byte = u8; -type byte = u8; -pub type PByte = *mut Byte; - -type EXPERIMENTAL_PCWEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST = - *const EXPERIMENTAL_WEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST; -pub type EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST = - *const EXPERIMENTAL_WEBAUTHN_PLUGIN_OPERATION_REQUEST; -pub type EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE = - *mut EXPERIMENTAL_WEBAUTHN_PLUGIN_OPERATION_RESPONSE; -pub type EXPERIMENTAL_PWEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE = - *mut EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE; - /// Handles initialization and registration for the Bitwarden desktop app as a /// plugin authenticator with Windows. /// For now, also adds the authenticator @@ -109,7 +65,8 @@ fn initialize_com_library() -> std::result::Result<(), String> { /// Registers the Bitwarden Plugin Authenticator COM library with Windows. fn register_com_library() -> std::result::Result<(), String> { - static FACTORY: windows_core::StaticComObject = Factory().into_static(); + static FACTORY: windows_core::StaticComObject = + pluginauthenticator::Factory().into_static(); let clsid: *const GUID = &GUID::from_u128(0xa98925d161f640de9327dc418fcb2ff4); match unsafe { @@ -146,25 +103,25 @@ fn add_authenticator() -> std::result::Result<(), String> { let cbor_authenticator_info = "A60182684649444F5F325F30684649444F5F325F310282637072666B686D61632D7365637265740350D548826E79B4DB40A3D811116F7E834904A362726BF5627570F5627576F5098168696E7465726E616C0A81A263616C672664747970656A7075626C69632D6B6579"; let mut authenticator_info_bytes = hex::decode(cbor_authenticator_info).unwrap(); - let add_authenticator_options = EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS { - pwszAuthenticatorName: authenticator_name_ptr, - pwszPluginClsId: clsid_ptr, - pwszPluginRpId: relying_party_id_ptr, - pwszLightThemeLogo: ptr::null(), // unused by Windows - pwszDarkThemeLogo: ptr::null(), // unused by Windows - cbAuthenticatorInfo: authenticator_info_bytes.len() as u32, - pbAuthenticatorInfo: authenticator_info_bytes.as_mut_ptr(), + let add_authenticator_options = webauthn::ExperimentalWebAuthnPluginAddAuthenticatorOptions { + authenticator_name: authenticator_name_ptr, + com_clsid: clsid_ptr, + rpid: relying_party_id_ptr, + light_theme_logo: ptr::null(), // unused by Windows + dark_theme_logo: ptr::null(), // unused by Windows + cbor_authenticator_info_byte_count: authenticator_info_bytes.len() as u32, + cbor_authenticator_info: authenticator_info_bytes.as_mut_ptr(), }; - let plugin_signing_public_key_byte_count: Dword = 0; + let plugin_signing_public_key_byte_count: u32 = 0; let mut plugin_signing_public_key: c_uchar = 0; - let plugin_signing_public_key_ptr: PByte = &mut plugin_signing_public_key; + let plugin_signing_public_key_ptr = &mut plugin_signing_public_key; - let mut add_response = EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE { - cbOpSignPubKey: plugin_signing_public_key_byte_count, - pbOpSignPubKey: plugin_signing_public_key_ptr, + let mut add_response = webauthn::ExperimentalWebAuthnPluginAddAuthenticatorResponse { + plugin_operation_signing_key_byte_count: plugin_signing_public_key_byte_count, + plugin_operation_signing_key: plugin_signing_public_key_ptr, }; - let mut add_response_ptr: *mut EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE = + let mut add_response_ptr: *mut webauthn::ExperimentalWebAuthnPluginAddAuthenticatorResponse = &mut add_response; let result = unsafe { @@ -193,23 +150,10 @@ fn add_authenticator() -> std::result::Result<(), String> { } } -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS { - pub pwszAuthenticatorName: *const u16, - pub pwszPluginClsId: *const u16, - pub pwszPluginRpId: *const u16, - pub pwszLightThemeLogo: *const u16, - pub pwszDarkThemeLogo: *const u16, - pub cbAuthenticatorInfo: u32, - pub pbAuthenticatorInfo: *const u8, -} - type EXPERIMENTAL_WebAuthNPluginAddAuthenticatorFnDeclaration = unsafe extern "cdecl" fn( - pPluginAddAuthenticatorOptions: *const EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS, - ppPluginAddAuthenticatorResponse: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE, -) - -> HRESULT; + pPluginAddAuthenticatorOptions: *const webauthn::ExperimentalWebAuthnPluginAddAuthenticatorOptions, + ppPluginAddAuthenticatorResponse: *mut *mut webauthn::ExperimentalWebAuthnPluginAddAuthenticatorResponse, +) -> HRESULT; unsafe fn delay_load(library: PCSTR, function: PCSTR) -> Option { let library = LoadLibraryExA(library, None, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); @@ -228,70 +172,3 @@ unsafe fn delay_load(library: PCSTR, function: PCSTR) -> Option { None } - -#[interface("e6466e9a-b2f3-47c5-b88d-89bc14a8d998")] -unsafe trait EXPERIMENTAL_IPluginAuthenticator: IUnknown { - fn EXPERIMENTAL_PluginMakeCredential( - &self, - request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST, - response: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE, - ) -> HRESULT; - fn EXPERIMENTAL_PluginGetAssertion( - &self, - request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST, - response: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE, - ) -> HRESULT; - fn EXPERIMENTAL_PluginCancelOperation( - &self, - request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST, - ) -> HRESULT; -} - -#[implement(EXPERIMENTAL_IPluginAuthenticator)] -struct PACOMObject; - -impl EXPERIMENTAL_IPluginAuthenticator_Impl for PACOMObject_Impl { - unsafe fn EXPERIMENTAL_PluginMakeCredential( - &self, - _request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST, - _response: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE, - ) -> HRESULT { - HRESULT(0) - } - - unsafe fn EXPERIMENTAL_PluginGetAssertion( - &self, - _request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST, - _response: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE, - ) -> HRESULT { - HRESULT(0) - } - - unsafe fn EXPERIMENTAL_PluginCancelOperation( - &self, - _request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST, - ) -> HRESULT { - HRESULT(0) - } -} - -#[implement(IClassFactory)] -struct Factory(); - -impl IClassFactory_Impl for Factory_Impl { - fn CreateInstance( - &self, - outer: Ref, - iid: *const GUID, - object: *mut *mut core::ffi::c_void, - ) -> Result<()> { - assert!(outer.is_null()); - let unknown: IInspectable = PACOMObject.into(); - unsafe { unknown.query(iid, object).ok() } - } - - fn LockServer(&self, lock: BOOL) -> Result<()> { - assert!(lock.as_bool()); - Ok(()) - } -} diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/pluginauthenticator.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/pluginauthenticator.rs new file mode 100644 index 00000000000..132f9effcde --- /dev/null +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/pluginauthenticator.rs @@ -0,0 +1,110 @@ +/* + This file exposes the functions and types defined here: https://github.com/microsoft/webauthn/blob/master/experimental/pluginauthenticator.h +*/ + +use windows::Win32::System::Com::*; +use windows_core::*; + +/// Used when creating and asserting credentials. +/// Header File Name: _EXPERIMENTAL_WEBAUTHN_PLUGIN_OPERATION_REQUEST +/// Header File Usage: EXPERIMENTAL_PluginMakeCredential() +/// EXPERIMENTAL_PluginGetAssertion() +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ExperimentalWebAuthnPluginOperationRequest { + 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 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 +/// Header File Usage: EXPERIMENTAL_PluginMakeCredential() +/// EXPERIMENTAL_PluginGetAssertion() +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ExperimentalWebAuthnPluginOperationResponse { + pub encoded_response_byte_count: u32, + pub encoded_response_pointer: *mut u8, +} + +/// Used to cancel an operation. +/// Header File Name: _EXPERIMENTAL_WEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST +/// Header File Usage: EXPERIMENTAL_PluginCancelOperation() +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ExperimentalWebAuthnPluginCancelOperationRequest { + pub transaction_id: windows_core::GUID, + pub request_signature_byte_count: u32, + pub request_signature_pointer: *mut u8, +} + +#[interface("e6466e9a-b2f3-47c5-b88d-89bc14a8d998")] +pub unsafe trait EXPERIMENTAL_IPluginAuthenticator: IUnknown { + fn EXPERIMENTAL_PluginMakeCredential( + &self, + request: *const ExperimentalWebAuthnPluginOperationRequest, + response: *mut ExperimentalWebAuthnPluginOperationResponse, + ) -> HRESULT; + fn EXPERIMENTAL_PluginGetAssertion( + &self, + request: *const ExperimentalWebAuthnPluginOperationRequest, + response: *mut ExperimentalWebAuthnPluginOperationResponse, + ) -> HRESULT; + fn EXPERIMENTAL_PluginCancelOperation( + &self, + request: *const ExperimentalWebAuthnPluginCancelOperationRequest, + ) -> HRESULT; +} + +#[implement(EXPERIMENTAL_IPluginAuthenticator)] +pub struct PluginAuthenticatorComObject; + +#[implement(IClassFactory)] +pub struct Factory(); + +impl EXPERIMENTAL_IPluginAuthenticator_Impl for PluginAuthenticatorComObject_Impl { + unsafe fn EXPERIMENTAL_PluginMakeCredential( + &self, + _request: *const ExperimentalWebAuthnPluginOperationRequest, + _response: *mut ExperimentalWebAuthnPluginOperationResponse, + ) -> HRESULT { + HRESULT(0) + } + + unsafe fn EXPERIMENTAL_PluginGetAssertion( + &self, + _request: *const ExperimentalWebAuthnPluginOperationRequest, + _response: *mut ExperimentalWebAuthnPluginOperationResponse, + ) -> HRESULT { + HRESULT(0) + } + + unsafe fn EXPERIMENTAL_PluginCancelOperation( + &self, + _request: *const ExperimentalWebAuthnPluginCancelOperationRequest, + ) -> HRESULT { + HRESULT(0) + } +} + +impl IClassFactory_Impl for Factory_Impl { + fn CreateInstance( + &self, + outer: Ref, + iid: *const GUID, + object: *mut *mut core::ffi::c_void, + ) -> Result<()> { + assert!(outer.is_null()); + let unknown: IInspectable = PluginAuthenticatorComObject.into(); + unsafe { unknown.query(iid, object).ok() } + } + + fn LockServer(&self, lock: BOOL) -> Result<()> { + assert!(lock.as_bool()); + Ok(()) + } +} diff --git a/apps/desktop/desktop_native/windows_plugin_authenticator/src/webauthn.rs b/apps/desktop/desktop_native/windows_plugin_authenticator/src/webauthn.rs new file mode 100644 index 00000000000..18c7563ffd8 --- /dev/null +++ b/apps/desktop/desktop_native/windows_plugin_authenticator/src/webauthn.rs @@ -0,0 +1,29 @@ +/* + This file exposes the functions and types defined here: https://github.com/microsoft/webauthn/blob/master/experimental/webauthn.h +*/ + +/// Used when adding a Windows plugin authenticator. +/// Header File Name: _EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS +/// Header File Usage: EXPERIMENTAL_WebAuthNPluginAddAuthenticator() +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ExperimentalWebAuthnPluginAddAuthenticatorOptions { + pub authenticator_name: *const u16, + pub com_clsid: *const u16, + pub rpid: *const u16, + pub light_theme_logo: *const u16, + pub dark_theme_logo: *const u16, + pub cbor_authenticator_info_byte_count: u32, + pub cbor_authenticator_info: *const u8, +} + +/// Used as a response type when adding a Windows plugin authenticator. +/// Header File Name: _EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE +/// Header File Usage: EXPERIMENTAL_WebAuthNPluginAddAuthenticator() +/// EXPERIMENTAL_WebAuthNPluginFreeAddAuthenticatorResponse() +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ExperimentalWebAuthnPluginAddAuthenticatorResponse { + pub plugin_operation_signing_key_byte_count: u32, + pub plugin_operation_signing_key: *mut u8, +}