Skip to content

Commit cdb8228

Browse files
Fixed issues with HMAC secret processing
1 parent 096f44c commit cdb8228

File tree

12 files changed

+228
-77
lines changed

12 files changed

+228
-77
lines changed

Documentation/CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
44

5+
## [1.0.3] - 2024-08-16
6+
7+
### Fixed
8+
9+
- Resolved issues with HMAC secret and linked device information processing.
10+
511
## [1.0.2] - 2024-08-13
612

713
### Fixed
@@ -18,6 +24,7 @@ All notable changes to this project will be documented in this file. The format
1824

1925
- Initial version
2026

21-
[Unreleased]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v1.0.2...HEAD
27+
[Unreleased]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v1.0.3...HEAD
28+
[1.0.3]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v1.0.2...v1.0.3
2229
[1.0.2]: https://github.com/MichaelGrafnetter/webauthn-interop/compare/v1.0...v1.0.2
2330
[1.0]: https://github.com/MichaelGrafnetter/webauthn-interop/releases/tag/v1.0

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 = '1.0.2'
11+
ModuleVersion = '1.0.3'
1212

1313
# Supported PSEditions
1414
CompatiblePSEditions = @('Desktop','Core')
@@ -108,7 +108,7 @@ PrivateData = @{
108108
IconUri = 'https://raw.githubusercontent.com/MichaelGrafnetter/DSInternals/master/Src/Icons/module_black.png'
109109

110110
# ReleaseNotes of this module
111-
ReleaseNotes = 'The module is now properly digitally signed. Note that the API is currently in public preview (beta).'
111+
ReleaseNotes = 'Fixed issues with HMAC secret processing. Note that the API is currently in public preview (beta).'
112112

113113
# Prerelease string of this module
114114
# Prerelease = ''

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>1.0.2</Version>
10-
<AssemblyVersion>1.0.2</AssemblyVersion>
11-
<ProductVersion>1.0.2</ProductVersion>
12-
<FileVersion>1.0.2</FileVersion>
9+
<Version>1.0.3</Version>
10+
<AssemblyVersion>1.0.3</AssemblyVersion>
11+
<ProductVersion>1.0.3</ProductVersion>
12+
<FileVersion>1.0.3</FileVersion>
1313
<Description>Bridge between Fido2.Models and DSInternals.Win32.WebAuthn packages</Description>
14-
<PackageReleaseNotes>- Initial release.
14+
<PackageReleaseNotes>- Fixed issues with HMAC secret processing.
1515
- Windows 10 1903 or newer is required.</PackageReleaseNotes>
1616
</PropertyGroup>
1717

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
<PackageId>DSInternals.Win32.WebAuthn</PackageId>
99
<Product>WebAuthn Interop Assembly</Product>
1010
<Title>WebAuthn Interop Assembly</Title>
11-
<Version>1.0.2</Version>
12-
<AssemblyVersion>1.0.2</AssemblyVersion>
13-
<ProductVersion>1.0.2</ProductVersion>
14-
<FileVersion>1.0.2</FileVersion>
11+
<Version>1.0.3</Version>
12+
<AssemblyVersion>1.0.3</AssemblyVersion>
13+
<ProductVersion>1.0.3</ProductVersion>
14+
<FileVersion>1.0.3</FileVersion>
1515
<Description>FIDO2 / W3C Web Authentication .NET Library for Windows Desktop and CLI Applications</Description>
16-
<PackageReleaseNotes>-Initial release.
16+
<PackageReleaseNotes>- Resolved issues with HMAC secret and linked device information processing.
1717
- Windows 10 1903 or newer is required.
1818
- A standalone package providing an adapter for data model defined in Fido2.Models is also available.</PackageReleaseNotes>
1919
</PropertyGroup>

Src/DSInternals.Win32.WebAuthn/Interop/Structs/CredentialWithHmacSecretSalt.cs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ internal class CredentialWithHmacSecretSaltIn : IDisposable
2020
/// <summary>
2121
/// PRF Values for above credential
2222
/// </summary>
23-
private HmacSecretSaltIn _hmacSecretSalt;
23+
private IntPtr _hmacSecretSalt;
2424

2525
/// <summary>
2626
/// Credential ID.
@@ -42,30 +42,50 @@ public byte[] CredentialId
4242
}
4343
}
4444

45+
/// <summary>
46+
/// PRF Values for above credential
47+
/// </summary>
4548
public HmacSecretSaltIn HmacSecretSalt
4649
{
4750
set
4851
{
49-
_hmacSecretSalt?.Dispose();
50-
_hmacSecretSalt = value;
52+
if(value != null)
53+
{
54+
if (_hmacSecretSalt == IntPtr.Zero)
55+
{
56+
_hmacSecretSalt = Marshal.AllocHGlobal(Marshal.SizeOf<HmacSecretSaltIn>());
57+
}
58+
59+
Marshal.StructureToPtr<HmacSecretSaltIn>(value, _hmacSecretSalt, false);
60+
}
61+
else
62+
{
63+
FreeHmacSecretSalt();
64+
}
5165
}
5266
}
5367

54-
public CredentialWithHmacSecretSaltIn(byte[] credentialId, byte[] first, byte[] second)
68+
public CredentialWithHmacSecretSaltIn(byte[] credentialId, HmacSecretSaltIn hmacSecretSalt)
5569
{
56-
// TODO: Validate that all parameters are present
5770
this.CredentialId = credentialId;
58-
this.HmacSecretSalt = new HmacSecretSaltIn(first, second);
59-
// TODO: Use tuples here
71+
this.HmacSecretSalt = hmacSecretSalt;
72+
}
73+
74+
private void FreeHmacSecretSalt()
75+
{
76+
if (_hmacSecretSalt != IntPtr.Zero)
77+
{
78+
Marshal.FreeHGlobal(_hmacSecretSalt);
79+
_hmacSecretSalt = IntPtr.Zero;
80+
}
6081
}
6182

6283
public void Dispose()
6384
{
6485
_credentialId?.Dispose();
6586
_credentialId = null;
6687

67-
_hmacSecretSalt?.Dispose();
68-
_hmacSecretSalt = null;
88+
FreeHmacSecretSalt();
6989
}
7090
}
7191

Src/DSInternals.Win32.WebAuthn/Interop/Structs/GetAssertion/Assertion.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Net;
1+
using System;
22
using System.Runtime.InteropServices;
33

44
namespace DSInternals.Win32.WebAuthn.Interop
@@ -79,13 +79,13 @@ internal sealed class Assertion
7979
/// A salt used to generate the HMAC secret.
8080
/// </summary>
8181
/// <remarks>This field has been added in WEBAUTHN_ASSERTION_VERSION_3.</remarks>
82-
public HmacSecretSaltOut HmacSecret { get; private set; }
82+
private IntPtr _hmacSecret;
8383

8484
/// <summary>
8585
/// The transport that was used.
8686
/// </summary>
8787
/// <remarks>This field has been added in WEBAUTHN_ASSERTION_VERSION_4.</remarks>
88-
public TransportContext UsedTransport { get; private set; }
88+
public AuthenticatorTransport UsedTransport { get; private set; }
8989

9090
/// <remarks>This field has been added in WEBAUTHN_ASSERTION_VERSION_5.</remarks>
9191
private int _unsignedExtensionOutputsLength;
@@ -118,5 +118,22 @@ internal sealed class Assertion
118118
/// </summary>
119119
/// <remarks>This field has been added in WEBAUTHN_ASSERTION_VERSION_5.</remarks>
120120
public byte[] UnsignedExtensionOutputs => _unsignedExtensionOutputs?.Read(_unsignedExtensionOutputsLength);
121+
122+
/// <summary>
123+
/// A salt used to generate the HMAC secret.
124+
/// </summary>
125+
/// <remarks>This field has been added in WEBAUTHN_ASSERTION_VERSION_3.</remarks>
126+
public HmacSecretSaltOut HmacSecret
127+
{
128+
get
129+
{
130+
if (_hmacSecret == IntPtr.Zero)
131+
{
132+
return null;
133+
}
134+
135+
return Marshal.PtrToStructure<HmacSecretSaltOut>(_hmacSecret);
136+
}
137+
}
121138
}
122139
}

Src/DSInternals.Win32.WebAuthn/Interop/Structs/GetAssertion/AuthenticatorGetAssertionOptions.cs

Lines changed: 89 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ internal class AuthenticatorGetAssertionOptions : IDisposable
9797
/// PRF values which will be converted into HMAC-SECRET values according to WebAuthn Specification.
9898
/// </summary>
9999
/// <remarks>This field has been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6.</remarks>
100-
private HmacSecretSaltValuesIn _hmacSecretSaltValues;
100+
private IntPtr _hmacSecretSaltValues;
101101

102102
/// <summary>
103103
/// Indicates whether the browser is in private mode. Defaulting to false.
@@ -109,7 +109,7 @@ internal class AuthenticatorGetAssertionOptions : IDisposable
109109
/// Linked Device Connection Info.
110110
/// </summary>
111111
/// <remarks>This field has been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_7.</remarks>
112-
public HybridStorageLinkedData LinkedDevice { get; set; }
112+
private IntPtr _linkedDevice { get; set; }
113113

114114
/// <summary>
115115
/// Allowlist MUST contain 1 credential applicable for Hybrid transport.
@@ -169,11 +169,7 @@ public Guid? CancellationId
169169
}
170170
else
171171
{
172-
if (_cancellationId != IntPtr.Zero)
173-
{
174-
Marshal.FreeHGlobal(_cancellationId);
175-
_cancellationId = IntPtr.Zero;
176-
}
172+
FreeCancellationId();
177173
}
178174
}
179175
}
@@ -208,11 +204,7 @@ public CredentialList AllowCredentialsEx
208204
}
209205
else
210206
{
211-
if (_allowCredentialList != IntPtr.Zero)
212-
{
213-
Marshal.FreeHGlobal(_allowCredentialList);
214-
_allowCredentialList = IntPtr.Zero;
215-
}
207+
FreeAllowCredentialList();
216208
}
217209
}
218210
}
@@ -265,23 +257,65 @@ public byte[] LargeBlob
265257
// Get rid of any previous blob first
266258
_largeBlob?.Dispose();
267259

268-
// Now replace the previous value with a new one
260+
// Now replace the previous value with the new one
269261
_largeBlobLength = value?.Length ?? 0;
270262
_largeBlob = new ByteArrayIn(value);
271263
}
272264
}
273265

266+
/// <summary>
267+
/// PRF values which will be converted into HMAC-SECRET values according to WebAuthn Specification.
268+
/// </summary>
269+
/// <remarks>This field has been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6.</remarks>
270+
274271
public HmacSecretSaltValuesIn HmacSecretSaltValues
275272
{
276273
set
277274
{
278-
_hmacSecretSaltValues?.Dispose();
279-
_hmacSecretSaltValues = value;
275+
if (value?.HasGlobalHmacSalt ?? false)
276+
{
277+
if (_hmacSecretSaltValues == IntPtr.Zero)
278+
{
279+
_hmacSecretSaltValues = Marshal.AllocHGlobal(Marshal.SizeOf<HmacSecretSaltValuesIn>());
280+
}
281+
282+
Marshal.StructureToPtr<HmacSecretSaltValuesIn>(value, _hmacSecretSaltValues, false);
283+
284+
// Set flag
285+
_flags |= AssertionOptionsFlags.AuthenticatorHmacSecretValues;
286+
}
287+
else
288+
{
289+
FreeHmacSecretSaltValues();
290+
291+
// Unset flag
292+
_flags &= ~AssertionOptionsFlags.AuthenticatorHmacSecretValues;
293+
}
294+
}
295+
}
296+
297+
/// <summary>
298+
/// Linked Device Connection Info.
299+
/// </summary>
300+
/// <remarks>This field has been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_7.</remarks>
301+
302+
public HybridStorageLinkedData LinkedDevice
303+
{
304+
set
305+
{
306+
if (value != null)
307+
{
308+
if (_linkedDevice == IntPtr.Zero)
309+
{
310+
_linkedDevice = Marshal.AllocHGlobal(Marshal.SizeOf<HybridStorageLinkedData>());
311+
}
280312

281-
// Set or unset the corresponding flag
282-
_flags = value != null ?
283-
_flags | AssertionOptionsFlags.AuthenticatorHmacSecretValues :
284-
_flags & ~AssertionOptionsFlags.AuthenticatorHmacSecretValues;
313+
Marshal.StructureToPtr<HybridStorageLinkedData>(value, _linkedDevice, false);
314+
}
315+
else
316+
{
317+
FreeLinkedDevice();
318+
}
285319
}
286320
}
287321

@@ -320,21 +354,50 @@ public void Dispose()
320354
_jsonExt?.Dispose();
321355
_jsonExt = null;
322356

323-
if (_allowCredentialList != IntPtr.Zero)
324-
{
325-
Marshal.FreeHGlobal(_allowCredentialList);
326-
_allowCredentialList = IntPtr.Zero;
327-
}
357+
FreeAllowCredentialList();
328358

329-
_hmacSecretSaltValues?.Dispose();
330-
_hmacSecretSaltValues = null;
359+
FreeHmacSecretSaltValues();
360+
361+
FreeLinkedDevice();
331362

332363
if (_isU2fAppIdUsed != IntPtr.Zero)
333364
{
334365
Marshal.FreeHGlobal(_isU2fAppIdUsed);
335366
_isU2fAppIdUsed = IntPtr.Zero;
336367
}
337368

369+
FreeCancellationId();
370+
}
371+
372+
private void FreeLinkedDevice()
373+
{
374+
if (_linkedDevice != IntPtr.Zero)
375+
{
376+
Marshal.FreeHGlobal(_linkedDevice);
377+
_linkedDevice = IntPtr.Zero;
378+
}
379+
}
380+
381+
private void FreeHmacSecretSaltValues()
382+
{
383+
if (_hmacSecretSaltValues != IntPtr.Zero)
384+
{
385+
Marshal.FreeHGlobal(_hmacSecretSaltValues);
386+
_hmacSecretSaltValues = IntPtr.Zero;
387+
}
388+
}
389+
390+
private void FreeAllowCredentialList()
391+
{
392+
if (_allowCredentialList != IntPtr.Zero)
393+
{
394+
Marshal.FreeHGlobal(_allowCredentialList);
395+
_allowCredentialList = IntPtr.Zero;
396+
}
397+
}
398+
399+
private void FreeCancellationId()
400+
{
338401
if (_cancellationId != IntPtr.Zero)
339402
{
340403
Marshal.FreeHGlobal(_cancellationId);

0 commit comments

Comments
 (0)