Skip to content

Commit 5f70de6

Browse files
Version 3 (#42)
- Data model improvements - Password manager export parsers
1 parent abf150d commit 5f70de6

162 files changed

Lines changed: 7410 additions & 2120 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ The [DSInternals.Passkeys](https://www.powershellgallery.com/packages/DSInternal
2727

2828
See [Yubico's blog](https://www.yubico.com/blog/microsoft-strengthens-phishing-resistant-security-for-entra-id-with-fido2-provisioning-apis/) for more details on the API.
2929

30-
## FIDO2 UI
30+
## Passkey UI
3131

32-
The project also contains a simple Windows GUI tool called `FIDO2 UI`, which is built on top of the `DSInternals.Win32.WebAuthn` library:
32+
The project also contains a simple Windows GUI tool called `Passkey UI`, which is built on top of the `DSInternals.Win32.WebAuthn` library:
3333

34-
![FIDO2 UI Screenshot](../Documentation/Screenshots/fido2_ui.png)
34+
![Passkey UI Screenshot](../Documentation/Screenshots/fido2_ui.png)
3535

3636
The only purpose of this tool is to demonstrate the usage of the WebAuthn API.
3737

@@ -42,7 +42,7 @@ The only purpose of this tool is to demonstrate the usage of the WebAuthn API.
4242
[![NuGet Gallery Downloads](https://img.shields.io/nuget/dt/DSInternals.Win32.WebAuthn.svg?label=NuGet%20Gallery%20Downloads&logo=NuGet)](https://www.nuget.org/packages/DSInternals.Win32.WebAuthn/)
4343

4444
- The `DSInternals.Passkeys` PowerShell module is published in the [PowerShell Gallery](https://www.powershellgallery.com/packages/DSInternals.Passkeys).
45-
- The latest version of the `FIDO2 UI` can be downloaded from the [Releases section](https://github.com/MichaelGrafnetter/webauthn-interop/releases/latest).
45+
- The latest version of the `Passkey UI` can be downloaded from the [Releases section](https://github.com/MichaelGrafnetter/webauthn-interop/releases/latest).
4646
- The `DSInternals.Win32.WebAuthn` library is published in the [NuGet Gallery](https://www.nuget.org/packages/DSInternals.Win32.WebAuthn/).
4747

4848
## .NET API Usage

Documentation/CHANGELOG.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. The format
44

55
## [Unreleased]
66

7+
## [3.0] - 2026-05-07
8+
9+
### Added
10+
11+
- Added Credential Exchange Format (CXF) parsing.
12+
- Added Bitwarden vault export support, covering both encrypted and cleartext exports.
13+
- Added KeePassXC passkey export parsing.
14+
- Added a software authenticator with Ed25519 signing for offline testing without a physical authenticator.
15+
- Added User Verification Method (UVM), Secure Payment Confirmation (SPC), PRF, Large Blob, Credential Properties, and Remote Desktop client override extension models.
16+
17+
### Changed
18+
19+
- Modernized the `WebAuthnApi` surface, including async cancellation handling and clearer marshaling of assertion/attestation options structs.
20+
721
## [2.1.1] - 2026-04-05
822

923
### Fixed
@@ -93,7 +107,9 @@ This is a bugfix release. Huge thanks to @aseigler for reporting and fixing the
93107

94108
- Initial version
95109

96-
[Unreleased]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v2.1...HEAD
110+
[Unreleased]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v3.0...HEAD
111+
[3.0]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v2.1.1...v3.0
112+
[2.1.1]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v2.1...v2.1.1
97113
[2.1]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v2.0...v2.1
98114
[2.0]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v1.0.6...v2.0
99115
[1.0.6]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v1.0.5...v1.0.6

Src/DSInternals.Passkeys/DSInternals.Passkeys.psd1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
RootModule = 'DSInternals.Passkeys.psm1'
99

1010
# Version number of this module.
11-
ModuleVersion = '2.1.1'
11+
ModuleVersion = '3.0.0'
1212

1313
# Supported PSEditions
1414
CompatiblePSEditions = @('Desktop','Core')
@@ -196,7 +196,7 @@ PrivateData = @{
196196

197197
# ReleaseNotes of this module
198198
ReleaseNotes = @'
199-
- Fixed CredentialId and AuthenticatorId properties not being displayed as Base64Url strings in the output of Get-PasskeyWindowsHello and Get-PasskeyAuthenticator cmdlets.
199+
- TODO
200200
'@
201201

202202
# Prerelease string of this module

Src/DSInternals.Passkeys/DSInternals.Passkeys.psm1

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ function New-Passkey
514514

515515
try {
516516
[DSInternals.Win32.WebAuthn.WebAuthnApi] $api = [DSInternals.Win32.WebAuthn.WebAuthnApi]::new()
517-
[DSInternals.Win32.WebAuthn.PublicKeyCredential] $credential = $api.AuthenticatorMakeCredential($Options.PublicKeyOptions)
517+
[DSInternals.Win32.WebAuthn.AttestationPublicKeyCredential] $credential = $api.AuthenticatorMakeCredential($Options.PublicKeyOptions)
518518

519519
switch ($Options.GetType()) {
520520
([DSInternals.Win32.WebAuthn.EntraID.MicrosoftGraphWebauthnCredentialCreationOptions]) {
@@ -594,7 +594,7 @@ Tests a passkey with a hint that a security key should be used.
594594
#>
595595
function Test-Passkey
596596
{
597-
[OutputType([DSInternals.Win32.WebAuthn.PublicKeyCredential])]
597+
[OutputType([DSInternals.Win32.WebAuthn.AssertionPublicKeyCredential])]
598598
[CmdletBinding()]
599599
param(
600600
[Parameter(Mandatory = $true)]
@@ -620,7 +620,7 @@ function Test-Passkey
620620

621621
[Parameter(Mandatory = $false)]
622622
[Alias("AuthenticatorType", "CredentialHint", "PublicKeyCredentialHint")]
623-
[DSInternals.Win32.WebAuthn.PublicKeyCredentialHint] $Hint
623+
[DSInternals.Win32.WebAuthn.PublicKeyCredentialHint] $Hint = [DSInternals.Win32.WebAuthn.PublicKeyCredentialHint]::None
624624
)
625625

626626
try {
@@ -642,6 +642,9 @@ function Test-Passkey
642642

643643
[DSInternals.Win32.WebAuthn.WebAuthnApi] $api = [DSInternals.Win32.WebAuthn.WebAuthnApi]::new()
644644

645+
[string] $credentialHint = [DSInternals.Win32.WebAuthn.PublicKeyCredentialHintExtensions]::ToJsonString($Hint)
646+
[string[]] $credentialHints = if (![string]::IsNullOrEmpty($credentialHint)) { @($credentialHint) } else { $null }
647+
645648
$response = $api.AuthenticatorGetAssertion(
646649
$RelyingPartyId,
647650
$challengeBytes,
@@ -650,14 +653,12 @@ function Test-Passkey
650653
$timeoutMilliseconds,
651654
$allowCredentials,
652655
$null, # extensions
653-
[DSInternals.Win32.WebAuthn.CredentialLargeBlobOperation]::None,
654-
$null, # largeBlob
655656
$false, # browserInPrivateMode
656657
$null, # linkedDevice
657658
$false, # autoFill
658-
$Hint, # credentialHints
659-
$null, # remoteWebOrigin
659+
$credentialHints,
660660
$null, # authenticatorId
661+
$null, # remoteWebOrigin
661662
$null, # publicKeyCredentialRequestOptionsJson
662663
[DSInternals.Win32.WebAuthn.WindowHandle]::ForegroundWindow
663664
)

Src/DSInternals.Win32.WebAuthn.Adapter.Tests/WebAuthnApiAdapterTester.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public void WebAuthN_MakeCredential_MSAccount()
7979
);
8080

8181
var webauthn = new WebAuthnApiAdapter();
82-
var response = webauthn.AuthenticatorMakeCredential(options);
82+
var response = RunInteractiveWebAuthnTest(() => webauthn.AuthenticatorMakeCredential(options));
8383

8484
Assert.IsNotNull(response);
8585
}
@@ -126,7 +126,7 @@ public void WebAuthN_GetAssertion_MSAccount_CredentialList()
126126
);
127127

128128
var webauthn = new WebAuthnApiAdapter();
129-
var response = webauthn.AuthenticatorGetAssertion(options);
129+
var response = RunInteractiveWebAuthnTest(() => webauthn.AuthenticatorGetAssertion(options));
130130

131131
Assert.IsNotNull(response);
132132
}
@@ -153,7 +153,8 @@ public void WebAuthN_GetAssertion_MSAccount_Usernameless()
153153
);
154154

155155
var webauthn = new WebAuthnApiAdapter();
156-
var response = webauthn.AuthenticatorGetAssertion(options, Fido2NetLib.Objects.AuthenticatorAttachment.Platform);
156+
var response = RunInteractiveWebAuthnTest(() =>
157+
webauthn.AuthenticatorGetAssertion(options, Fido2NetLib.Objects.AuthenticatorAttachment.Platform));
157158

158159
Assert.IsNotNull(response);
159160
}
@@ -184,5 +185,22 @@ public void WebAuthN_GetAssertion_Cancel()
184185
Assert.ThrowsExactly<OperationCanceledException>(() =>
185186
webauthn.AuthenticatorGetAssertionAsync(options, null, source.Token).GetAwaiter().GetResult());
186187
}
188+
189+
[System.Diagnostics.CodeAnalysis.SuppressMessage("MSTest.Analyzers", "MSTEST0025", Justification = "Uses AssertInconclusiveException when interactive WebAuthn UI is unavailable.")]
190+
private static T RunInteractiveWebAuthnTest<T>(Func<T> action)
191+
{
192+
try
193+
{
194+
return action();
195+
}
196+
catch (Exception ex) when (IsInteractiveWebAuthnUnavailable(ex))
197+
{
198+
throw new AssertInconclusiveException("Interactive WebAuthn UI is unavailable or was cancelled in this test environment.", ex);
199+
}
200+
}
201+
202+
private static bool IsInteractiveWebAuthnUnavailable(Exception ex) =>
203+
ex is UnauthorizedAccessException or OperationCanceledException or System.ComponentModel.Win32Exception
204+
|| ex.InnerException is System.ComponentModel.Win32Exception { NativeErrorCode: 5 or 1223 };
187205
}
188206
}

Src/DSInternals.Win32.WebAuthn.Adapter.Tests/packages.lock.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@
4949
"resolved": "9.18.0",
5050
"contentHash": "jlgewzgbgEFIoplbpdWNPKo/+R9ELej0iL1sdKrVeMzQ0aZCvRCdi/X/4AjRaBqkXoDTWFrOjgVXRukZYSVO+w=="
5151
},
52+
"libsodium": {
53+
"type": "Transitive",
54+
"resolved": "1.0.20.1",
55+
"contentHash": "pkiceEqJDQFHjbga3k/oPfTVX9g+GKJZ1VrkuiLhaymt9YNw1Dr7cX9hNuZuNaWcr9WD0moW55k4pMwzQ7JaZQ=="
56+
},
5257
"Microsoft.ApplicationInsights": {
5358
"type": "Transitive",
5459
"resolved": "2.23.0",
@@ -170,6 +175,7 @@
170175
"Microsoft.Bcl.Memory": "[10.0.5, )",
171176
"Microsoft.Identity.Client": "[4.80.0, )",
172177
"Microsoft.NET.ILLink.Tasks": "[10.0.3, )",
178+
"NSec.Cryptography": "[25.4.0, )",
173179
"System.Diagnostics.EventLog": "[9.0.3, )",
174180
"System.Formats.Cbor": "[9.0.3, )",
175181
"System.IdentityModel.Tokens.Jwt": "[8.15.0, )"
@@ -178,7 +184,7 @@
178184
"dsinternals.win32.webauthn.adapter": {
179185
"type": "Project",
180186
"dependencies": {
181-
"DSInternals.Win32.WebAuthn": "[2.0.0, )",
187+
"DSInternals.Win32.WebAuthn": "[2.1.0, )",
182188
"Fido2.Models": "[4.0.0, )",
183189
"Microsoft.Bcl.Memory": "[10.0.5, )"
184190
}
@@ -213,6 +219,15 @@
213219
"resolved": "10.0.3",
214220
"contentHash": "0B6nZyCHWXnvmlB559oduOspVdNOnpNXPjhpWVMovLPAsDVG7A4jJR9rzECf67JUzxP8/ee/wA8clwIzJcWNFA=="
215221
},
222+
"NSec.Cryptography": {
223+
"type": "CentralTransitive",
224+
"requested": "[25.4.0, )",
225+
"resolved": "25.4.0",
226+
"contentHash": "Z3wPpG0xefMLmhn9T+Ka/EzAmMQPT0THL/5E4lf9cXI/N9rbGH0G23ZFpRcPnD0ast2k7ieG6QSVNIjmfPCXBQ==",
227+
"dependencies": {
228+
"libsodium": "[1.0.20.1, 1.0.21)"
229+
}
230+
},
216231
"System.Diagnostics.EventLog": {
217232
"type": "CentralTransitive",
218233
"requested": "[9.0.3, )",

Src/DSInternals.Win32.WebAuthn.Adapter/DSInternals.Win32.WebAuthn.Adapter.csproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<PackageId>DSInternals.Win32.WebAuthn.Adapter</PackageId>
77
<Product>WebAuthn Interop Assembly Adapter</Product>
88
<Title>WebAuthn Interop Assembly Adapter</Title>
9-
<Version>2.1.0</Version>
10-
<AssemblyVersion>2.1.0</AssemblyVersion>
11-
<ProductVersion>2.1.0</ProductVersion>
12-
<FileVersion>2.1.0</FileVersion>
9+
<Version>3.0.0</Version>
10+
<AssemblyVersion>3.0.0</AssemblyVersion>
11+
<ProductVersion>3.0.0</ProductVersion>
12+
<FileVersion>3.0.0</FileVersion>
1313
<Description>Bridge between Fido2.Models and DSInternals.Win32.WebAuthn packages</Description>
14-
<PackageReleaseNotes>- Updated DSInternals.Win32.WebAuthn dependency to 2.1.0.</PackageReleaseNotes>
14+
<PackageReleaseNotes>- Updated DSInternals.Win32.WebAuthn dependency to 3.0.0 and aligned with the new API surface.</PackageReleaseNotes>
1515
</PropertyGroup>
1616

1717
<PropertyGroup Condition="'$(Configuration)'=='Release'">

Src/DSInternals.Win32.WebAuthn.Adapter/packages.lock.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
"resolved": "9.18.0",
2424
"contentHash": "jlgewzgbgEFIoplbpdWNPKo/+R9ELej0iL1sdKrVeMzQ0aZCvRCdi/X/4AjRaBqkXoDTWFrOjgVXRukZYSVO+w=="
2525
},
26+
"libsodium": {
27+
"type": "Transitive",
28+
"resolved": "1.0.20.1",
29+
"contentHash": "pkiceEqJDQFHjbga3k/oPfTVX9g+GKJZ1VrkuiLhaymt9YNw1Dr7cX9hNuZuNaWcr9WD0moW55k4pMwzQ7JaZQ=="
30+
},
2631
"Microsoft.Extensions.DependencyInjection.Abstractions": {
2732
"type": "Transitive",
2833
"resolved": "10.0.0",
@@ -72,6 +77,7 @@
7277
"Microsoft.Bcl.Memory": "[10.0.5, )",
7378
"Microsoft.Identity.Client": "[4.80.0, )",
7479
"Microsoft.NET.ILLink.Tasks": "[10.0.3, )",
80+
"NSec.Cryptography": "[25.4.0, )",
7581
"System.Diagnostics.EventLog": "[9.0.3, )",
7682
"System.Formats.Cbor": "[9.0.3, )",
7783
"System.IdentityModel.Tokens.Jwt": "[8.15.0, )"
@@ -92,6 +98,15 @@
9298
"resolved": "10.0.3",
9399
"contentHash": "0B6nZyCHWXnvmlB559oduOspVdNOnpNXPjhpWVMovLPAsDVG7A4jJR9rzECf67JUzxP8/ee/wA8clwIzJcWNFA=="
94100
},
101+
"NSec.Cryptography": {
102+
"type": "CentralTransitive",
103+
"requested": "[25.4.0, )",
104+
"resolved": "25.4.0",
105+
"contentHash": "Z3wPpG0xefMLmhn9T+Ka/EzAmMQPT0THL/5E4lf9cXI/N9rbGH0G23ZFpRcPnD0ast2k7ieG6QSVNIjmfPCXBQ==",
106+
"dependencies": {
107+
"libsodium": "[1.0.20.1, 1.0.21)"
108+
}
109+
},
95110
"System.Diagnostics.EventLog": {
96111
"type": "CentralTransitive",
97112
"requested": "[9.0.3, )",

0 commit comments

Comments
 (0)