Make concurrent calls forwarded unconditionally. It is now up to the native API whether it will honor the request or return an error.
Additionally, fix an error in AuthenticatorAssertionResponse data marshalling.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <OutputType>library</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Runtime.InteropServices;
using static Interop;
using static Tizen.Security.WebAuthn.ErrorFactory;
{
private const int API_VERSION_NUMBER = 0x00000001;
private static bool _apiVersionSet = false;
- private static bool _busy = false;
private static object _userData = null;
- private static WauthnDisplayQrcodeCallback _qrCodeCallback;
- private static WauthnMcOnResponseCallback _mcResponseCallback;
- private static WauthnGaOnResponseCallback _gaResponseCallback;
- private static WauthnUpdateLinkedDataCallback _linkedDataCallback;
- private static WauthnMcCallbacks _wauthnMcCallbacks;
- private static WauthnGaCallbacks _wauthnGaCallbacks;
+ private static Dictionary<int, AuthenticatorStorage> _apiCalls = new();
+ private static int _callId = 0;
#region Public API
/// <summary>
public static void MakeCredential(ClientData clientData, PubkeyCredCreationOptions options, MakeCredentialCallbacks callbacks)
{
CheckPreconditions();
- try
- {
- CheckNullNThrow(clientData);
- CheckNullNThrow(clientData.JsonData);
- CheckNullNThrow(options);
- CheckNullNThrow(options.Rp);
- CheckNullNThrow(options.User);
- CheckNullNThrow(options.PubkeyCredParams);
- CheckNullNThrow(callbacks);
- CheckNullNThrow(callbacks.QrcodeCallback);
- CheckNullNThrow(callbacks.ResponseCallback);
- CheckNullNThrow(callbacks.LinkedDataCallback);
+ CheckNullNThrow(clientData);
+ CheckNullNThrow(clientData.JsonData);
+ CheckNullNThrow(options);
+ CheckNullNThrow(options.Rp);
+ CheckNullNThrow(options.User);
+ CheckNullNThrow(options.PubkeyCredParams);
+ CheckNullNThrow(callbacks);
+ CheckNullNThrow(callbacks.QrcodeCallback);
+ CheckNullNThrow(callbacks.ResponseCallback);
+ CheckNullNThrow(callbacks.LinkedDataCallback);
- // Create callback wrappers
- WrapMcCallbacks(callbacks);
- AuthenticatorStorage.SetDataForMakeCredential(clientData, options);
+ int id = unchecked(_callId++);
+ // Copy data to unmanaged memory
+ var storage = new AuthenticatorMakeCredentialStorage(clientData, options);
+ // Create callback wrappers
+ WrapMcCallbacks(callbacks, storage, id);
+ // Add the storage to a static dictionary to prevent GC from premature collecting
+ _apiCalls.Add(id, storage);
+ try
+ {
int ret = Libwebauthn.MakeCredential(
- AuthenticatorStorage.WauthnClientData,
- AuthenticatorStorage.WauthnPubkeyCredCreationOptions,
- _wauthnMcCallbacks);
+ storage.WauthnClientData,
+ storage.WauthnPubkeyCredCreationOptions,
+ storage.WauthnMcCallbacks);
CheckErrNThrow(ret, "Make Credential");
}
catch
{
- Cleanup();
+ Cleanup(id);
throw;
}
}
public static void GetAssertion(ClientData clientData, PubkeyCredRequestOptions options, GetAssertionCallbacks callbacks)
{
CheckPreconditions();
- try
- {
- CheckNullNThrow(clientData);
- CheckNullNThrow(clientData.JsonData);
- CheckNullNThrow(options);
- CheckNullNThrow(callbacks);
- CheckNullNThrow(callbacks.QrcodeCallback);
- CheckNullNThrow(callbacks.ResponseCallback);
- CheckNullNThrow(callbacks.LinkedDataCallback);
+ CheckNullNThrow(clientData);
+ CheckNullNThrow(clientData.JsonData);
+ CheckNullNThrow(options);
+ CheckNullNThrow(callbacks);
+ CheckNullNThrow(callbacks.QrcodeCallback);
+ CheckNullNThrow(callbacks.ResponseCallback);
+ CheckNullNThrow(callbacks.LinkedDataCallback);
- // Create callback wrappers
- WrapGaCallbacks(callbacks);
- AuthenticatorStorage.SetDataForGetAssertion(clientData, options);
+ int id = unchecked(_callId++);
+ // Copy data to unmanaged memory
+ var storage = new AuthenticatorGetAssertionStorage(clientData, options);
+ // Create callback wrappers
+ WrapGaCallbacks(callbacks, storage, id);
+ // Add the storage to a static dictionary to prevent GC from premature collecting
+ _apiCalls.Add(id, storage);
+ try
+ {
int ret = Libwebauthn.GetAssertion(
- AuthenticatorStorage.WauthnClientData,
- AuthenticatorStorage.WauthnPubkeyCredRequestOptions,
- _wauthnGaCallbacks);
+ storage.WauthnClientData,
+ storage.WauthnPubkeyCredRequestOptions,
+ storage.WauthnGaCallbacks);
CheckErrNThrow(ret, "Get Assertion");
}
catch
{
- Cleanup();
+ Cleanup(id);
throw;
}
}
CheckErrNThrow(ret, "Set API version");
_apiVersionSet = true;
}
- private static void WrapMcCallbacks(MakeCredentialCallbacks callbacks)
+ private static void WrapMcCallbacks(MakeCredentialCallbacks callbacks, AuthenticatorMakeCredentialStorage storage, int id)
{
_userData = callbacks.UserData;
callbacks.ResponseCallback(pubkeyCredManaged, result, _userData);
if (result != WauthnError.None)
- Cleanup();
+ Cleanup(id);
}
void linkedDataWrapper(IntPtr linkedData, WauthnError result, IntPtr _)
callbacks.LinkedDataCallback(linkedDataManaged, result, _userData);
if (result != WauthnError.NoneAndWait)
- Cleanup();
+ Cleanup(id);
}
- _qrCodeCallback = new WauthnDisplayQrcodeCallback(qrCodeWrapper);
- _mcResponseCallback = new WauthnMcOnResponseCallback(onResponseWrapper);
- _linkedDataCallback = new WauthnUpdateLinkedDataCallback(linkedDataWrapper);
-
- _wauthnMcCallbacks = new WauthnMcCallbacks(_qrCodeCallback, _mcResponseCallback, _linkedDataCallback);
+ storage.SetCallbacks(
+ new WauthnDisplayQrcodeCallback(qrCodeWrapper),
+ new WauthnMcOnResponseCallback(onResponseWrapper),
+ new WauthnUpdateLinkedDataCallback(linkedDataWrapper)
+ );
}
- private static void WrapGaCallbacks(GetAssertionCallbacks callbacks)
+ private static void WrapGaCallbacks(GetAssertionCallbacks callbacks, AuthenticatorGetAssertionStorage storage, int id)
{
_userData = callbacks.UserData;
callbacks.ResponseCallback(pubkeyCredManaged, result, _userData);
if (result != WauthnError.None)
- Cleanup();
+ Cleanup(id);
}
void linkedDataWrapper(IntPtr linkedData, WauthnError result, IntPtr _)
callbacks.LinkedDataCallback(linkedDataManaged, result, _userData);
if (result != WauthnError.NoneAndWait)
- Cleanup();
+ Cleanup(id);
}
- _qrCodeCallback = new WauthnDisplayQrcodeCallback(qrCodeWrapper);
- _gaResponseCallback = new WauthnGaOnResponseCallback(onResponseWrapper);
- _linkedDataCallback = new WauthnUpdateLinkedDataCallback(linkedDataWrapper);
- _wauthnGaCallbacks = new WauthnGaCallbacks(_qrCodeCallback, _gaResponseCallback, _linkedDataCallback);
+ storage.SetCallbacks(
+ new WauthnDisplayQrcodeCallback(qrCodeWrapper),
+ new WauthnGaOnResponseCallback(onResponseWrapper),
+ new WauthnUpdateLinkedDataCallback(linkedDataWrapper)
+ );
}
private static void CheckPreconditions()
{
if (!_apiVersionSet)
SetApiVersion(API_VERSION_NUMBER);
- if (_busy)
- throw new InvalidOperationException("Authenticator busy");
-
- _busy = true;
}
- private static void Cleanup()
+ private static void Cleanup(int id)
{
- _busy = false;
- AuthenticatorStorage.Cleanup();
+ _apiCalls[id]?.Dispose();
+ _apiCalls.Remove(id);
}
#endregion
internal AuthenticatorAssertionResponse(WauthnAuthenticatorAssertionResponse wauthnResponse)
{
ClientDataJson = NullSafeMarshal.PtrToArray(wauthnResponse.clientDataJson);
- AuthenticatorData = NullSafeMarshal.PtrToArray(wauthnResponse.attestationObject);
+ AuthenticatorData = NullSafeMarshal.PtrToArray(wauthnResponse.authenticatorData);
Signature = NullSafeMarshal.PtrToArray(wauthnResponse.signature);
UserHandle = NullSafeMarshal.PtrToArray(wauthnResponse.userHandle);
AttestationObject = NullSafeMarshal.PtrToArray(wauthnResponse.attestationObject);
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+using static Interop;
+
+namespace Tizen.Security.WebAuthn
+{
+ internal class AuthenticatorGetAssertionStorage : AuthenticatorStorage
+ {
+ private WauthnGaOnResponseCallback _responseCallback;
+ private bool _disposed = false;
+
+ public AuthenticatorGetAssertionStorage(ClientData clientData, PubkeyCredRequestOptions options)
+ {
+ CopyClientData(clientData);
+ CopyCredRequestOptions(options);
+ }
+
+ public void SetCallbacks(
+ WauthnDisplayQrcodeCallback qrcodeCallback,
+ WauthnGaOnResponseCallback responseCallback,
+ WauthnUpdateLinkedDataCallback linkedDataCallback)
+ {
+ _qrcodeCallback = qrcodeCallback;
+ _responseCallback = responseCallback;
+ _linkedDataCallback = linkedDataCallback;
+
+ WauthnGaCallbacks = new WauthnGaCallbacks(_qrcodeCallback, _responseCallback, _linkedDataCallback);
+ }
+
+ public override void Dispose()
+ {
+ if (_disposed)
+ return;
+
+ base.Dispose();
+
+ _disposed = true;
+ }
+
+ private void CopyCredRequestOptions(PubkeyCredRequestOptions options)
+ {
+ CopyCredentials(options.AllowCredentials);
+ CopyHints(options.Hints);
+ CopyAttestationFormats(options.AttestationFormats);
+ CopyExtensions(options.Extensions);
+ CopyLinkedDevice(options.LinkedDevice);
+ WauthnPubkeyCredRequestOptions = new WauthnPubkeyCredRequestOptions(
+ (nuint)options.Timeout,
+ options.RpId,
+ _credentialsUnmanaged,
+ options.UserVerification,
+ _hintsUnmanaged,
+ options.Attestation,
+ _attestationFormatsUnmanaged,
+ _extensionsUnmanaged,
+ _linkedDeviceUnmanaged);
+ }
+
+ public WauthnGaCallbacks WauthnGaCallbacks { get; private set; }
+ public WauthnPubkeyCredRequestOptions WauthnPubkeyCredRequestOptions { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+using System.Collections.Generic;
+using System.Linq;
+using static Interop;
+
+namespace Tizen.Security.WebAuthn
+{
+ internal class AuthenticatorMakeCredentialStorage : AuthenticatorStorage
+ {
+ #region Internal unmanaged memory
+ private UnmanagedMemory _rpNameUnmanaged = new();
+ private UnmanagedMemory _rpIdUnmanaged = new();
+ private UnmanagedMemory _rpUnmanaged = new();
+ private UnmanagedMemory _userNameUnmanaged = new();
+ private UnmanagedMemory _userIdDataUnmanaged = new();
+ private UnmanagedMemory _userIdConstBufferUnmanaged = new();
+ private UnmanagedMemory _userDisplayNameUnmanaged = new();
+ private UnmanagedMemory _userUnmanaged = new();
+ private UnmanagedMemory _pubkeyCredParamsParametersUnmanaged = new();
+ private UnmanagedMemory _pubkeyCredParamsUnmanaged = new();
+ private UnmanagedMemory _authenticatorSelectionUnmanaged = new();
+
+ private WauthnMcOnResponseCallback _responseCallback;
+ #endregion
+
+ private bool _disposed = false;
+
+ public AuthenticatorMakeCredentialStorage(ClientData clientData, PubkeyCredCreationOptions options)
+ {
+ CopyClientData(clientData);
+ CopyCredCreationOptions(options);
+ }
+
+ public void SetCallbacks(
+ WauthnDisplayQrcodeCallback qrcodeCallback,
+ WauthnMcOnResponseCallback responseCallback,
+ WauthnUpdateLinkedDataCallback linkedDataCallback)
+ {
+ _qrcodeCallback = qrcodeCallback;
+ _responseCallback = responseCallback;
+ _linkedDataCallback = linkedDataCallback;
+
+ WauthnMcCallbacks = new WauthnMcCallbacks(_qrcodeCallback, _responseCallback, _linkedDataCallback);
+ }
+
+ public override void Dispose()
+ {
+ if (_disposed)
+ return;
+
+ _rpNameUnmanaged.Dispose();
+ _rpIdUnmanaged.Dispose();
+ _rpUnmanaged.Dispose();
+ _userNameUnmanaged.Dispose();
+ _userIdConstBufferUnmanaged.Dispose();
+ _userDisplayNameUnmanaged.Dispose();
+ _userUnmanaged.Dispose();
+ _pubkeyCredParamsParametersUnmanaged.Dispose();
+ _pubkeyCredParamsUnmanaged.Dispose();
+
+ base.Dispose();
+
+ _disposed = true;
+ }
+
+ #region Data marshalling
+ private void CopyCredCreationOptions(PubkeyCredCreationOptions options)
+ {
+ CopyRp(options.Rp);
+ CopyUser(options.User);
+ CopyCredParams(options.PubkeyCredParams);
+ CopyCredentials(options.ExcludeCredentials);
+ CopyAuthenticatorSelection(options.AuthenticatorSelection);
+ CopyHints(options.Hints);
+ CopyAttestationFormats(options.AttestationFormats);
+ CopyExtensions(options.Extensions);
+ CopyLinkedDevice(options.LinkedDevice);
+
+ WauthnPubkeyCredCreationOptions = new WauthnPubkeyCredCreationOptions(
+ _rpUnmanaged,
+ _userUnmanaged,
+ _pubkeyCredParamsUnmanaged,
+ (nuint)options.Timeout,
+ _credentialsUnmanaged,
+ _authenticatorSelectionUnmanaged,
+ _hintsUnmanaged,
+ options.Attestation,
+ _attestationFormatsUnmanaged,
+ _extensionsUnmanaged,
+ _linkedDeviceUnmanaged);
+ }
+
+ private void CopyRp(RelyingPartyEntity rp)
+ {
+ _rpNameUnmanaged = new UnmanagedMemory(rp.Name);
+ _rpIdUnmanaged = new UnmanagedMemory(rp.Id);
+ _rpUnmanaged = new UnmanagedMemory(new WauthnRpEntity(_rpNameUnmanaged, _rpIdUnmanaged));
+ }
+
+ private void CopyUser(UserEntity user)
+ {
+ _userNameUnmanaged = new UnmanagedMemory(user.Name);
+ _userIdDataUnmanaged = UnmanagedMemory.PinArray(user.Id);
+ _userIdConstBufferUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_userIdDataUnmanaged, (nuint)user.Id.Length));
+ _userDisplayNameUnmanaged = new UnmanagedMemory(user.DisplayName);
+ _userUnmanaged = new UnmanagedMemory(new WauthnUserEntity(
+ _userNameUnmanaged,
+ _userIdConstBufferUnmanaged,
+ _userDisplayNameUnmanaged));
+ }
+
+ private void CopyCredParams(IEnumerable<PubkeyCredParam> credParams)
+ {
+ if (credParams is null || !credParams.Any())
+ return;
+
+ WauthnPubkeyCredParam[] pubkeyCredParamStructArray = credParams.Select((PubkeyCredParam param) => new WauthnPubkeyCredParam(param.Type, param.Alg)).ToArray();
+ _pubkeyCredParamsParametersUnmanaged = UnmanagedMemory.PinArray(pubkeyCredParamStructArray);
+ _pubkeyCredParamsUnmanaged = new UnmanagedMemory(new WauthnPubkeyCredParams((nuint)pubkeyCredParamStructArray.Length, _pubkeyCredParamsParametersUnmanaged));
+ }
+
+ protected void CopyAuthenticatorSelection(AuthenticationSelectionCriteria selection)
+ {
+ if (selection is null)
+ return;
+
+ _authenticatorSelectionUnmanaged = new UnmanagedMemory(new WauthnAuthenticationSelCri(
+ selection.Attachment,
+ selection.ResidentKey,
+ (byte)(selection.RequireResidentKey ? 1 : 0),
+ selection.UserVerification));
+ }
+ #endregion
+
+ public WauthnMcCallbacks WauthnMcCallbacks { get; private set; }
+ public WauthnPubkeyCredCreationOptions WauthnPubkeyCredCreationOptions { get; private set; }
+ }
+}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.InteropServices;
using static Interop;
-using static Tizen.Security.WebAuthn.ErrorFactory;
namespace Tizen.Security.WebAuthn
{
- internal static class AuthenticatorStorage
+ internal abstract class AuthenticatorStorage : IDisposable
{
#region Internal unmanaged memory
- private static UnmanagedMemory[] _credentialsIdUnmanagedDataArray;
- private static UnmanagedMemory[] _credentialsIdUnmanagedConstBufferArray;
- private static UnmanagedMemory[] _attestationFormatsUnmanagedDataArray;
- private static UnmanagedMemory[] _attestationFormatsUnmanagedConstBufferArray;
- private static UnmanagedMemory[] _extensionIdUnmanagedDataArray;
- private static UnmanagedMemory[] _extensionIdUnmanagedConstBufferArray;
- private static UnmanagedMemory[] _extensionValueUnmanagedDataArray;
- private static UnmanagedMemory[] _extensionValueUnmanagedConstBufferArray;
- private static UnmanagedMemory _jsonDataUnmanaged = new();
- private static UnmanagedMemory _jsonDataConstBufferUnmanaged = new();
- private static UnmanagedMemory _rpNameUnmanaged = new();
- private static UnmanagedMemory _rpIdUnmanaged = new();
- private static UnmanagedMemory _rpUnmanaged = new();
- private static UnmanagedMemory _userNameUnmanaged = new();
- private static UnmanagedMemory _userIdDataUnmanaged = new();
- private static UnmanagedMemory _userIdConstBufferUnmanaged = new();
- private static UnmanagedMemory _userDisplayNameUnmanaged = new();
- private static UnmanagedMemory _userUnmanaged = new();
- private static UnmanagedMemory _pubkeyCredParamsParametersUnmanaged = new();
- private static UnmanagedMemory _pubkeyCredParamsUnmanaged = new();
- private static UnmanagedMemory _credentialsDescriptorsUnmanaged = new();
- private static UnmanagedMemory _credentialsUnmanaged = new();
- private static UnmanagedMemory _authenticatorSelectionUnmanaged = new();
- private static UnmanagedMemory _hintsArrayUnmanaged = new();
- private static UnmanagedMemory _hintsUnmanaged = new();
- private static UnmanagedMemory _attestationFormatsArrayUnmanaged = new();
- private static UnmanagedMemory _attestationFormatsUnmanaged = new();
- private static UnmanagedMemory _extensionsArrayUnmanaged = new();
- private static UnmanagedMemory _extensionsUnmanaged = new();
- private static UnmanagedMemory _contactIdDataUnmanaged = new();
- private static UnmanagedMemory _contactIdUnmanaged = new();
- private static UnmanagedMemory _linkIdDataUnmanaged = new();
- private static UnmanagedMemory _linkIdUnmanaged = new();
- private static UnmanagedMemory _linkSecretDataUnmanaged = new();
- private static UnmanagedMemory _linkSecretUnmanaged = new();
- private static UnmanagedMemory _authenticatorPubkeyDataUnmanaged = new();
- private static UnmanagedMemory _authenticatorPubkeyUnmanaged = new();
- private static UnmanagedMemory _authenticatorNameDataUnmanaged = new();
- private static UnmanagedMemory _authenticatorNameUnmanaged = new();
- private static UnmanagedMemory _signatureDataUnmanaged = new();
- private static UnmanagedMemory _signatureUnmanaged = new();
- private static UnmanagedMemory _tunnelServerDomainDataUnmanaged = new();
- private static UnmanagedMemory _tunnelServerDomainUnmanaged = new();
- private static UnmanagedMemory _identityKeyDataUnmanaged = new();
- private static UnmanagedMemory _identityKeyUnmanaged = new();
- private static UnmanagedMemory _linkedDeviceUnmanaged = new();
+ protected UnmanagedMemory _credentialsUnmanaged = new();
+ protected UnmanagedMemory _hintsUnmanaged = new();
+ protected UnmanagedMemory _attestationFormatsUnmanaged = new();
+ protected UnmanagedMemory _extensionsUnmanaged = new();
+ protected UnmanagedMemory _linkedDeviceUnmanaged = new();
+
+ protected WauthnDisplayQrcodeCallback _qrcodeCallback;
+ protected WauthnUpdateLinkedDataCallback _linkedDataCallback;
+
+ private UnmanagedMemory[] _credentialsIdUnmanagedDataArray;
+ private UnmanagedMemory[] _credentialsIdUnmanagedConstBufferArray;
+ private UnmanagedMemory[] _attestationFormatsUnmanagedDataArray;
+ private UnmanagedMemory[] _attestationFormatsUnmanagedConstBufferArray;
+ private UnmanagedMemory[] _extensionIdUnmanagedDataArray;
+ private UnmanagedMemory[] _extensionIdUnmanagedConstBufferArray;
+ private UnmanagedMemory[] _extensionValueUnmanagedDataArray;
+ private UnmanagedMemory[] _extensionValueUnmanagedConstBufferArray;
+
+ private UnmanagedMemory _jsonDataUnmanaged = new();
+ private UnmanagedMemory _jsonDataConstBufferUnmanaged = new();
+ private UnmanagedMemory _credentialsDescriptorsUnmanaged = new();
+ private UnmanagedMemory _hintsArrayUnmanaged = new();
+ private UnmanagedMemory _attestationFormatsArrayUnmanaged = new();
+ private UnmanagedMemory _extensionsArrayUnmanaged = new();
+ private UnmanagedMemory _contactIdDataUnmanaged = new();
+ private UnmanagedMemory _contactIdUnmanaged = new();
+ private UnmanagedMemory _linkIdDataUnmanaged = new();
+ private UnmanagedMemory _linkIdUnmanaged = new();
+ private UnmanagedMemory _linkSecretDataUnmanaged = new();
+ private UnmanagedMemory _linkSecretUnmanaged = new();
+ private UnmanagedMemory _authenticatorPubkeyDataUnmanaged = new();
+ private UnmanagedMemory _authenticatorPubkeyUnmanaged = new();
+ private UnmanagedMemory _authenticatorNameDataUnmanaged = new();
+ private UnmanagedMemory _authenticatorNameUnmanaged = new();
+ private UnmanagedMemory _signatureDataUnmanaged = new();
+ private UnmanagedMemory _signatureUnmanaged = new();
+ private UnmanagedMemory _tunnelServerDomainDataUnmanaged = new();
+ private UnmanagedMemory _tunnelServerDomainUnmanaged = new();
+ private UnmanagedMemory _identityKeyDataUnmanaged = new();
+ private UnmanagedMemory _identityKeyUnmanaged = new();
#endregion
- public static void SetDataForMakeCredential(ClientData clientData, PubkeyCredCreationOptions options)
- {
- CopyClientData(clientData);
- CopyCredCreationOptions(options);
- }
+ private bool _disposed = false;
- public static void SetDataForGetAssertion(ClientData clientData, PubkeyCredRequestOptions options)
+ public virtual void Dispose()
{
- CopyClientData(clientData);
- CopyCredRequestOptions(options);
- }
+ if (_disposed)
+ return;
- public static void Cleanup()
- {
CleanupArray(_credentialsIdUnmanagedDataArray);
CleanupArray(_credentialsIdUnmanagedConstBufferArray);
CleanupArray(_attestationFormatsUnmanagedDataArray);
_jsonDataUnmanaged.Dispose();
_jsonDataConstBufferUnmanaged.Dispose();
- _rpNameUnmanaged.Dispose();
- _rpIdUnmanaged.Dispose();
- _rpUnmanaged.Dispose();
- _userNameUnmanaged.Dispose();
- _userIdConstBufferUnmanaged.Dispose();
- _userDisplayNameUnmanaged.Dispose();
- _userUnmanaged.Dispose();
- _pubkeyCredParamsParametersUnmanaged.Dispose();
- _pubkeyCredParamsUnmanaged.Dispose();
_credentialsDescriptorsUnmanaged.Dispose();
_credentialsUnmanaged.Dispose();
- _authenticatorSelectionUnmanaged.Dispose();
_hintsArrayUnmanaged.Dispose();
_hintsUnmanaged.Dispose();
_attestationFormatsArrayUnmanaged.Dispose();
_identityKeyDataUnmanaged.Dispose();
_identityKeyUnmanaged.Dispose();
_linkedDeviceUnmanaged.Dispose();
+
+ _disposed = true;
}
- private static void CopyClientData(ClientData clientData)
+ #region Data marshalling
+ protected void CopyClientData(ClientData clientData)
{
_jsonDataUnmanaged = UnmanagedMemory.PinArray(clientData.JsonData);
_jsonDataConstBufferUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_jsonDataUnmanaged, (nuint)clientData.JsonData.Length));
WauthnClientData = new WauthnClientData(_jsonDataConstBufferUnmanaged, clientData.HashAlgo);
}
- private static void CopyCredCreationOptions(PubkeyCredCreationOptions options)
- {
- CopyRp(options.Rp);
- CopyUser(options.User);
- CopyCredParams(options.PubkeyCredParams);
- CopyCredentials(options.ExcludeCredentials);
- CopyAuthenticatorSelection(options.AuthenticatorSelection);
- CopyHints(options.Hints);
- CopyAttestationFormats(options.AttestationFormats);
- CopyExtensions(options.Extensions);
- CopyLinkedDevice(options.LinkedDevice);
-
- WauthnPubkeyCredCreationOptions = new WauthnPubkeyCredCreationOptions(
- _rpUnmanaged,
- _userUnmanaged,
- _pubkeyCredParamsUnmanaged,
- (nuint)options.Timeout,
- _credentialsUnmanaged,
- _authenticatorSelectionUnmanaged,
- _hintsUnmanaged,
- options.Attestation,
- _attestationFormatsUnmanaged,
- _extensionsUnmanaged,
- _linkedDeviceUnmanaged);
- }
-
- private static void CopyCredRequestOptions(PubkeyCredRequestOptions options)
- {
- CopyCredentials(options.AllowCredentials);
- CopyHints(options.Hints);
- CopyAttestationFormats(options.AttestationFormats);
- CopyExtensions(options.Extensions);
- CopyLinkedDevice(options.LinkedDevice);
- WauthnPubkeyCredRequestOptions = new WauthnPubkeyCredRequestOptions(
- (nuint)options.Timeout,
- options.RpId,
- _credentialsUnmanaged,
- options.UserVerification,
- _hintsUnmanaged,
- options.Attestation,
- _attestationFormatsUnmanaged,
- _extensionsUnmanaged,
- _linkedDeviceUnmanaged);
- }
-
- private static void CopyRp(RelyingPartyEntity rp)
- {
- _rpNameUnmanaged = new UnmanagedMemory(rp.Name);
- _rpIdUnmanaged = new UnmanagedMemory(rp.Id);
- _rpUnmanaged = new UnmanagedMemory(new WauthnRpEntity(_rpNameUnmanaged, _rpIdUnmanaged));
- }
-
- private static void CopyUser(UserEntity user)
- {
- _userNameUnmanaged = new UnmanagedMemory(user.Name);
- _userIdDataUnmanaged = UnmanagedMemory.PinArray(user.Id);
- _userIdConstBufferUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_userIdDataUnmanaged, (nuint)user.Id.Length));
- _userDisplayNameUnmanaged = new UnmanagedMemory(user.DisplayName);
- _userUnmanaged = new UnmanagedMemory(new WauthnUserEntity(
- _userNameUnmanaged,
- _userIdConstBufferUnmanaged,
- _userDisplayNameUnmanaged));
- }
-
- private static void CopyCredParams(IEnumerable<PubkeyCredParam> credParams)
- {
- if (credParams is null || !credParams.Any())
- return;
-
- WauthnPubkeyCredParam[] pubkeyCredParamStructArray = credParams.Select((PubkeyCredParam param) => new WauthnPubkeyCredParam(param.Type, param.Alg)).ToArray();
- _pubkeyCredParamsParametersUnmanaged = UnmanagedMemory.PinArray(pubkeyCredParamStructArray);
- _pubkeyCredParamsUnmanaged = new UnmanagedMemory(new WauthnPubkeyCredParams((nuint)pubkeyCredParamStructArray.Length, _pubkeyCredParamsParametersUnmanaged));
- }
-
- private static void CopyCredentials(IEnumerable<PubkeyCredDescriptor> credentials)
+ protected void CopyCredentials(IEnumerable<PubkeyCredDescriptor> credentials)
{
if (credentials is null || !credentials.Any())
return;
_credentialsUnmanaged = new UnmanagedMemory(new WauthnPubkeyCredDescriptors((nuint)credentialsCount, _credentialsDescriptorsUnmanaged));
}
- private static void CopyAuthenticatorSelection(AuthenticationSelectionCriteria selection)
- {
- if (selection is null)
- return;
-
- _authenticatorSelectionUnmanaged = new UnmanagedMemory(new WauthnAuthenticationSelCri(
- selection.Attachment,
- selection.ResidentKey,
- (byte)(selection.RequireResidentKey ? 1 : 0),
- selection.UserVerification));
- }
-
- private static void CopyHints(IEnumerable<PubkeyCredHint> hints)
+ protected void CopyHints(IEnumerable<PubkeyCredHint> hints)
{
if (hints is null || !hints.Any())
return;
_hintsUnmanaged = new UnmanagedMemory(new WauthnPubkeyCredHints((nuint)hintsArray.Length, _hintsArrayUnmanaged));
}
- private static void CopyAttestationFormats(IEnumerable<byte[]> attestationFormats)
+ protected void CopyAttestationFormats(IEnumerable<byte[]> attestationFormats)
{
if (attestationFormats is null || !attestationFormats.Any())
return;
_attestationFormatsUnmanaged = new UnmanagedMemory(new WauthnAttestationFormats((nuint)attestationFormatsCount, _attestationFormatsArrayUnmanaged));
}
- private static void CopyExtensions(IEnumerable<AuthenticationExtension> extensions)
+ protected void CopyExtensions(IEnumerable<AuthenticationExtension> extensions)
{
if (extensions is null || !extensions.Any())
return;
_extensionsUnmanaged = new UnmanagedMemory(new WauthnAuthenticationExts((nuint)extensionCount, _extensionsArrayUnmanaged));
}
- private static void CopyLinkedDevice(HybridLinkedData linkedDevice)
+ protected void CopyLinkedDevice(HybridLinkedData linkedDevice)
{
if (linkedDevice is null)
return;
_signatureUnmanaged,
_tunnelServerDomainUnmanaged,
_identityKeyUnmanaged));
-
- if (_linkedDeviceUnmanaged == IntPtr.Zero)
- throw new TimeoutException("linked null");
}
+ #endregion
- public static void CleanupArray(UnmanagedMemory[] array)
+ protected static void CleanupArray(UnmanagedMemory[] array)
{
if (array is null)
return;
memory.Dispose();
}
- public static WauthnClientData WauthnClientData { get; private set; }
- public static WauthnPubkeyCredCreationOptions WauthnPubkeyCredCreationOptions { get; private set; }
- public static WauthnPubkeyCredRequestOptions WauthnPubkeyCredRequestOptions { get; private set; }
+ public WauthnClientData WauthnClientData { get; private set; }
}
}
\ No newline at end of file