diff --git a/src/Tizen.Security.WebAuthn/Interop/Interop.Libweabuthn.cs b/src/Tizen.Security.WebAuthn/Interop/Interop.Libweabuthn.cs new file mode 100644 index 00000000000..27ba520ba03 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Interop/Interop.Libweabuthn.cs @@ -0,0 +1,49 @@ +/* + * 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; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Libraries + { + public const string Libwebauthn = "libwebauthn-client.so.1"; + } + + internal static partial class Libwebauthn + { + [DllImport(Libraries.Libwebauthn, EntryPoint = "wauthn_set_api_version", CallingConvention = CallingConvention.Cdecl)] + public static extern int SetApiVersion(int apiVersionNumber); + // int wauthn_set_api_version(int api_version_number); + + [DllImport(Libraries.Libwebauthn, EntryPoint = "wauthn_supported_authenticators", CallingConvention = CallingConvention.Cdecl)] + public static extern int SupportedAuthenticators(out uint supported); + // int wauthn_supported_authenticators(unsigned int *supported); + + [DllImport(Libraries.Libwebauthn, EntryPoint = "wauthn_make_credential", CallingConvention = CallingConvention.Cdecl)] + public static extern int MakeCredential([In] WauthnClientData clientData, [In] WauthnPubkeyCredCreationOptions options, [In, Out] WauthnMcCallbacks callbacks); + // int wauthn_make_credential( const wauthn_client_data_s *client_data, const wauthn_pubkey_cred_creation_options_s *options, wauthn_mc_callbacks_s *callbacks); + + [DllImport(Libraries.Libwebauthn, EntryPoint = "wauthn_get_assertion", CallingConvention = CallingConvention.Cdecl)] + public static extern int GetAssertion([In] WauthnClientData clientData, [In] WauthnPubkeyCredRequestOptions options, [In, Out] WauthnGaCallbacks callbacks); + // int wauthn_get_assertion( const wauthn_client_data_s *client_data, const wauthn_pubkey_cred_request_options_s *options, wauthn_ga_callbacks_s *callbacks); + + [DllImport(Libraries.Libwebauthn, EntryPoint = "wauthn_cancel", CallingConvention = CallingConvention.Cdecl)] + public static extern int Cancel(); + // int wauthn_cancel(); + } +} diff --git a/src/Tizen.Security.WebAuthn/Interop/Interop.Types.cs b/src/Tizen.Security.WebAuthn/Interop/Interop.Types.cs new file mode 100644 index 00000000000..c85dbd09d19 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Interop/Interop.Types.cs @@ -0,0 +1,521 @@ +/* + * 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; +using System.Runtime.InteropServices; +using Tizen.Internals; +using Tizen.Security.WebAuthn; + +internal static partial class Interop +{ + private const string pkg = "webauthn"; + + #region Delegates + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void WauthnDisplayQrcodeCallback([In][MarshalAs(UnmanagedType.LPStr)] string qrContents, IntPtr userData); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void WauthnMcOnResponseCallback([In] WauthnPubkeyCredentialAttestation pubkeyCred, WauthnError result, IntPtr userData); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void WauthnGaOnResponseCallback([In] WauthnPubkeyCredentialAssertion pubkeyCred, WauthnError result, IntPtr userData); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void WauthnUpdateLinkedDataCallback([In] IntPtr linkedData, WauthnError result, IntPtr userData); + + #endregion + #region Classes + + [NativeStruct("wauthn_rp_entity_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnRpEntity + { + public readonly IntPtr name; // string + public readonly IntPtr id; // string + + public WauthnRpEntity(IntPtr name, IntPtr id) + { + this.name = name; + this.id = id; + } + } + + [NativeStruct("wauthn_user_entity_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnUserEntity + { + public readonly IntPtr name; // string + public readonly IntPtr id; // WauthnConstBuffer* + public readonly IntPtr displayName; // string + + public WauthnUserEntity(IntPtr name, IntPtr id, IntPtr displayName) + { + this.name = name; + this.id = id; + this.displayName = displayName; + } + } + + [NativeStruct("wauthn_pubkey_cred_params_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnPubkeyCredParams + { + public readonly nuint size; + public readonly IntPtr parameters; // WauthnPubkeyCredParam[] + + public WauthnPubkeyCredParams(nuint size, IntPtr parameters) + { + this.size = size; + this.parameters = parameters; + } + } + + [NativeStruct("wauthn_pubkey_cred_descriptors_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnPubkeyCredDescriptors + { + public readonly nuint size; + public readonly IntPtr descriptors; // WauthnPubkeyCredDescriptor[] + + public WauthnPubkeyCredDescriptors(nuint size, IntPtr descriptors) + { + this.size = size; + this.descriptors = descriptors; + } + } + + [NativeStruct("wauthn_authenticator_sel_cri_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnAuthenticationSelCri + { + public readonly AuthenticatorAttachment attachment; + public readonly ResidentKeyRequirement residentKey; + public readonly byte requireResidentKey; + public readonly UserVerificationRequirement userVerification; + + public WauthnAuthenticationSelCri( + AuthenticatorAttachment attachment, + ResidentKeyRequirement residentKey, + byte requireResidentKey, + UserVerificationRequirement userVerification) + { + this.attachment = attachment; + this.residentKey = residentKey; + this.requireResidentKey = requireResidentKey; + this.userVerification = userVerification; + } + } + + [NativeStruct("wauthn_pubkey_cred_hints_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnPubkeyCredHints + { + public readonly nuint size; + public readonly IntPtr hints; // PubkeyCredHint[] + + public WauthnPubkeyCredHints(nuint size, IntPtr hints) + { + this.size = size; + this.hints = hints; + } + } + + [NativeStruct("wauthn_attestation_formats_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnAttestationFormats + { + public readonly nuint size; + public readonly IntPtr attestationFormats; // WauthnConstBuffer[] + + public WauthnAttestationFormats(nuint size, IntPtr attestationFormats) + { + this.size = size; + this.attestationFormats = attestationFormats; + } + } + + [NativeStruct("wauthn_pubkey_cred_creation_options_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnPubkeyCredCreationOptions + { + public readonly IntPtr rp; // WauthnRpEntity* + public readonly IntPtr user; // WauthnUserEntity* + public readonly IntPtr pubkeyCredParams; // WauthnPubkeyCredParams* + public readonly nuint timeout; + public readonly IntPtr excludeCredentials; // WauthnPubkeyCredDescriptors* + public readonly IntPtr authenticatorSelection; // WauthnAuthenticationSelCri* + public readonly IntPtr hints; // WauthnPubkeyCredHints* + public readonly AttestationPref attestation; + public readonly IntPtr attestationFormats; // WauthnAttestationFormats* + public readonly IntPtr extensions; // WauthnAuthenticationExts* + public readonly IntPtr linkedDevice; // WauthnHybridLinkedData* + + public WauthnPubkeyCredCreationOptions( + IntPtr rp, + IntPtr user, + IntPtr pubkeyCredParams, + nuint timeout, + IntPtr excludeCredentials, + IntPtr authenticatorSelection, + IntPtr hints, + AttestationPref attestation, + IntPtr attestationFormats, + IntPtr extensions, + IntPtr linkedDevice) + { + this.rp = rp; + this.user = user; + this.pubkeyCredParams = pubkeyCredParams; + this.timeout = timeout; + this.excludeCredentials = excludeCredentials; + this.authenticatorSelection = authenticatorSelection; + this.hints = hints; + this.attestation = attestation; + this.attestationFormats = attestationFormats; + this.extensions = extensions; + this.linkedDevice = linkedDevice; + } + } + + [NativeStruct("wauthn_pubkey_cred_request_options_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnPubkeyCredRequestOptions + { + public readonly nuint timeout; + [MarshalAs(UnmanagedType.LPStr)] + public readonly string rpId; + public readonly IntPtr allowCredentials; // WauthnPubkeyCredDescriptors* + public readonly UserVerificationRequirement userVerification; + public readonly IntPtr hints; // WauthnPubkeyCredHints* + public readonly AttestationPref attestation; + public readonly IntPtr attestationFormats; // WauthnAttestationFormats* + public readonly IntPtr extensions; // WauthnAuthenticationExt* + public readonly IntPtr linkedDevice; // WauthnHybridLinkedData* + + public WauthnPubkeyCredRequestOptions( + nuint timeout, + string rpId, + IntPtr allowCredentials, + UserVerificationRequirement userVerification, + IntPtr hints, + AttestationPref attestation, + IntPtr attestationFormats, + IntPtr extensions, + IntPtr linkedDevice) + { + this.timeout = timeout; + this.rpId = rpId; + this.allowCredentials = allowCredentials; + this.userVerification = userVerification; + this.hints = hints; + this.attestation = attestation; + this.attestationFormats = attestationFormats; + this.extensions = extensions; + this.linkedDevice = linkedDevice; + } + } + + [NativeStruct("wauthn_pubkey_credential_attestation_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnPubkeyCredentialAttestation + { + public readonly IntPtr id; // WauthnConstBuffer* + public readonly PubkeyCredType type; + public readonly IntPtr rawId; // WauthnConstBuffer* + public readonly IntPtr response; // WauthnAuthenticatorAttestationResponse* + public readonly AuthenticatorAttachment authenticatorAttachment; + public readonly IntPtr extensions; // WauthnAuthenticationExts* + public readonly IntPtr linkedDevice; // WauthnHybridLinkedData* + + public WauthnPubkeyCredentialAttestation( + IntPtr id, + PubkeyCredType type, + IntPtr rawId, + IntPtr response, + AuthenticatorAttachment authenticatorAttachment, + IntPtr extensions, + IntPtr linkedDevice) + { + this.id = id; + this.type = type; + this.rawId = rawId; + this.response = response; + this.authenticatorAttachment = authenticatorAttachment; + this.extensions = extensions; + this.linkedDevice = linkedDevice; + } + } + + [NativeStruct("wauthn_pubkey_credential_assertion_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnPubkeyCredentialAssertion + { + public readonly IntPtr id; // WauthnConstBuffer* + public readonly PubkeyCredType type; + public readonly IntPtr rawId; // WauthnConstBuffer* + public readonly IntPtr response; // WauthnAuthenticatorAssertionResponse* + public readonly AuthenticatorAttachment authenticatorAttachment; + public readonly IntPtr extensions; // WauthnAuthenticationExts* + public readonly IntPtr linkedDevice; // WauthnHybridLinkedData* + + public WauthnPubkeyCredentialAssertion( + IntPtr id, + IntPtr rawId, + IntPtr response, + AuthenticatorAttachment authenticatorAttachment, + IntPtr extensions, + IntPtr linkedDevice) + { + this.id = id; + this.rawId = rawId; + this.response = response; + this.authenticatorAttachment = authenticatorAttachment; + this.extensions = extensions; + this.linkedDevice = linkedDevice; + } + } + + [NativeStruct("wauthn_client_data_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnClientData + { + public readonly IntPtr clientDataJson; // WauthnConstBuffer* + public readonly HashAlgorithm hashAlgo; + + public WauthnClientData(IntPtr clientDataJson, HashAlgorithm hashAlgo) + { + this.clientDataJson = clientDataJson; + this.hashAlgo = hashAlgo; + } + } + + [NativeStruct("wauthn_mc_callbacks_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnMcCallbacks + { + [MarshalAs(UnmanagedType.FunctionPtr)] + public readonly WauthnDisplayQrcodeCallback qrcodeCallback; + [MarshalAs(UnmanagedType.FunctionPtr)] + public readonly WauthnMcOnResponseCallback responseCallback; + [MarshalAs(UnmanagedType.FunctionPtr)] + public readonly WauthnUpdateLinkedDataCallback linkedDataCallback; + public readonly IntPtr userData = IntPtr.Zero; + + public WauthnMcCallbacks( + WauthnDisplayQrcodeCallback qrcodeCallback, + WauthnMcOnResponseCallback responseCallback, + WauthnUpdateLinkedDataCallback linkedDataCallback) + { + this.qrcodeCallback = qrcodeCallback; + this.responseCallback = responseCallback; + this.linkedDataCallback = linkedDataCallback; + } + } + + [NativeStruct("wauthn_ga_callbacks_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class WauthnGaCallbacks + { + [MarshalAs(UnmanagedType.FunctionPtr)] + public readonly WauthnDisplayQrcodeCallback qrcodeCallback; + [MarshalAs(UnmanagedType.FunctionPtr)] + public readonly WauthnGaOnResponseCallback responseCallback; + [MarshalAs(UnmanagedType.FunctionPtr)] + public readonly WauthnUpdateLinkedDataCallback linkedDataCallback; + public readonly IntPtr userData = IntPtr.Zero; + + public WauthnGaCallbacks( + WauthnDisplayQrcodeCallback qrcodeCallback, + WauthnGaOnResponseCallback responseCallback, + WauthnUpdateLinkedDataCallback linkedDataCallback) + { + this.qrcodeCallback = qrcodeCallback; + this.responseCallback = responseCallback; + this.linkedDataCallback = linkedDataCallback; + } + } + #endregion + #region Structs + + [NativeStruct("wauthn_const_buffer_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct WauthnConstBuffer + { + public readonly IntPtr data; // byte[] + public readonly nuint size; + + public WauthnConstBuffer(IntPtr data, nuint size) + { + this.data = data; + this.size = size; + } + + public readonly byte[] ToArray() + { + var ret = new byte[size]; + Marshal.Copy(data, ret, 0, (int)size); + return ret; + } + } + + [NativeStruct("wauthn_authenticator_attestation_response_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct WauthnAuthenticatorAttestationResponse + { + public readonly IntPtr clientDataJson; // WauthnConstBuffer* + public readonly IntPtr attestationObject; // WauthnConstBuffer* + public readonly uint transports; + public readonly IntPtr authenticatorData; // WauthnConstBuffer* + public readonly IntPtr subjectPubkeyInfo; // WauthnConstBuffer* + public readonly CoseAlgorithm pubkeyAlg; + + public WauthnAuthenticatorAttestationResponse( + IntPtr clientDataJson, + IntPtr attestationObject, + uint transports, + IntPtr authenticatorData, + IntPtr subjectPubkeyInfo, + CoseAlgorithm pubkeyAlg) + { + this.clientDataJson = clientDataJson; + this.attestationObject = attestationObject; + this.transports = transports; + this.authenticatorData = authenticatorData; + this.subjectPubkeyInfo = subjectPubkeyInfo; + this.pubkeyAlg = pubkeyAlg; + } + } + + [NativeStruct("wauthn_authenticator_assertion_response_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct WauthnAuthenticatorAssertionResponse + { + public readonly IntPtr clientDataJson; // WauthnConstBuffer* + public readonly IntPtr authenticatorData; // WauthnConstBuffer* + public readonly IntPtr signature; // WauthnConstBuffer* + public readonly IntPtr userHandle; // WauthnConstBuffer* + public readonly IntPtr attestationObject; // WauthnConstBuffer* + + public WauthnAuthenticatorAssertionResponse( + IntPtr clientDataJson, + IntPtr authenticatorData, + IntPtr signature, + IntPtr userHandle, + IntPtr attestationObject) + { + this.clientDataJson = clientDataJson; + this.authenticatorData = authenticatorData; + this.signature = signature; + this.userHandle = userHandle; + this.attestationObject = attestationObject; + } + } + + [NativeStruct("wauthn_pubkey_cred_param_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct WauthnPubkeyCredParam + { + public readonly PubkeyCredType type; + public readonly CoseAlgorithm alg; + + public WauthnPubkeyCredParam(PubkeyCredType type, CoseAlgorithm alg) + { + this.type = type; + this.alg = alg; + } + } + + [NativeStruct("wauthn_pubkey_cred_descriptor_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct WauthnPubkeyCredDescriptor + { + public readonly PubkeyCredType type; + public readonly IntPtr id; // WauthnConstBuffer* + public readonly AuthenticatorTransport transport; + + public WauthnPubkeyCredDescriptor(PubkeyCredType type, IntPtr id, AuthenticatorTransport transport) + { + this.type = type; + this.id = id; + this.transport = transport; + } + } + + [NativeStruct("wauthn_authentication_ext_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct WauthnAuthenticationExt + { + public readonly IntPtr extensionId; // WauthnConstBuffer* + public readonly IntPtr extensionValue; // WauthnConstBuffer* + + public WauthnAuthenticationExt(IntPtr extensionId, IntPtr extensionValue) + { + this.extensionId = extensionId; + this.extensionValue = extensionValue; + } + } + + [NativeStruct("wauthn_authentication_exts_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct WauthnAuthenticationExts + { + public readonly nuint size; + public readonly IntPtr descriptors; // WauthnAuthenticationExt[] + + public WauthnAuthenticationExts(nuint size, IntPtr descriptors) + { + this.size = size; + this.descriptors = descriptors; + } + } + + [NativeStruct("wauthn_hybrid_linked_data_s", Include="webauthn-types.h", PkgConfig=pkg)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct WauthnHybridLinkedData + { + public readonly IntPtr contactId; // WauthnConstBuffer* + public readonly IntPtr linkId; // WauthnConstBuffer* + public readonly IntPtr linkSecret; // WauthnConstBuffer* + public readonly IntPtr authenticatorPubkey; // WauthnConstBuffer* + public readonly IntPtr authenticatorName; // WauthnConstBuffer* + public readonly IntPtr signature; // WauthnConstBuffer* + public readonly IntPtr tunnelServerDomain; // WauthnConstBuffer* + public readonly IntPtr identityKey; // WauthnConstBuffer* + + public WauthnHybridLinkedData( + IntPtr contactId, + IntPtr linkId, + IntPtr linkSecret, + IntPtr authenticatorPubkey, + IntPtr authenticatorName, + IntPtr signature, + IntPtr tunnelServerDomain, + IntPtr identityKey) + { + this.contactId = contactId; + this.linkId = linkId; + this.linkSecret = linkSecret; + this.authenticatorPubkey = authenticatorPubkey; + this.authenticatorName = authenticatorName; + this.signature = signature; + this.tunnelServerDomain = tunnelServerDomain; + this.identityKey = identityKey; + } + } + + #endregion +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn.csproj b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn.csproj new file mode 100644 index 00000000000..bb1db212d74 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn.csproj @@ -0,0 +1,11 @@ + + + + library + net6.0 + + + + + + diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn.sln b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn.sln new file mode 100644 index 00000000000..c045ea994f6 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Security.WebAuthn", "Tizen.Security.WebAuthn.csproj", "{CEC2F310-E4BA-4FDB-8B06-8AA73C006ABC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CEC2F310-E4BA-4FDB-8B06-8AA73C006ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CEC2F310-E4BA-4FDB-8B06-8AA73C006ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEC2F310-E4BA-4FDB-8B06-8AA73C006ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CEC2F310-E4BA-4FDB-8B06-8AA73C006ABC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {52E8477B-782E-40D2-B5F2-9047EE144C1A} + EndGlobalSection +EndGlobal diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticationExtension.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticationExtension.cs new file mode 100644 index 00000000000..630461152db --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticationExtension.cs @@ -0,0 +1,58 @@ +/* + * 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; +using static Tizen.Security.WebAuthn.ErrorFactory; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Authenticator extension. + /// + /// 12 + public class AuthenticationExtension + { + /// + /// Initializes a new instance of the class. + /// + /// 12 + /// + /// Extension Identifier defined in the following registry: + /// https://www.iana.org/assignments/webauthn/webauthn.xhtml#webauthn-extension-ids + /// + /// Extension value. + public AuthenticationExtension(byte[] extensionId, byte[] extensionValue) + { + ExtensionId = extensionId; + ExtensionValue = extensionValue; + } + + internal AuthenticationExtension(WauthnAuthenticationExt ext) + { + ExtensionId = NullSafeMarshal.PtrToArray(ext.extensionId); + ExtensionValue = NullSafeMarshal.PtrToArray(ext.extensionValue); + } + + /// + /// Extension identifier. + /// + public byte[] ExtensionId { get; init; } + /// + /// Extension value. + /// + public byte[] ExtensionValue { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticationSelectionCriteria.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticationSelectionCriteria.cs new file mode 100644 index 00000000000..1f4714caa56 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticationSelectionCriteria.cs @@ -0,0 +1,62 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// Authenticator selection criteria. + /// + /// 12 + public class AuthenticationSelectionCriteria + { + /// + /// Initializes a new instance of the class. + /// + /// 12 + /// Authenticator attachment modality. + /// Specifies the extent to which the Relying Party desires to create a client-side discoverable credential. + /// Relying Parties SHOULD set it to true if, and only if, residentKey is set to required. + /// Specifies the Relying Party's requirements regarding user verification. + public AuthenticationSelectionCriteria( + AuthenticatorAttachment attachment, + ResidentKeyRequirement residentKey, + bool requireResidentKey, + UserVerificationRequirement userVerification) + { + Attachment = attachment; + ResidentKey = residentKey; + RequireResidentKey = requireResidentKey; + UserVerification = userVerification; + } + + /// + /// Authenticator attachment modality. + /// + public AuthenticatorAttachment Attachment { get; init; } + /// + /// The extent to which the Relying Party desires to create a client-side discoverable credential. + /// + public ResidentKeyRequirement ResidentKey { get; init; } + /// + /// Whether residentKey is required. + /// + public bool RequireResidentKey { get; init; } + /// + /// The Relying Party's requirements regarding user verification. + /// + public UserVerificationRequirement UserVerification { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Authenticator.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Authenticator.cs new file mode 100644 index 00000000000..68707c8b3a7 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Authenticator.cs @@ -0,0 +1,283 @@ +/* + * 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; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using static Interop; +using static Tizen.Security.WebAuthn.ErrorFactory; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Public web authentication API. + /// + /// 12 + public static class Authenticator + { + 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; + + #region Public API + /// + /// Gets information on authenticator types that the client platform supports. + /// + /// 12 + /// http://tizen.org/feature/security.webauthn + /// An enum with the collection of all supported authenticator types. + /// The required feature is not supported. + public static AuthenticatorTransport SupportedAuthenticators() + { + int ret = Libwebauthn.SupportedAuthenticators(out uint supported); + CheckErrNThrow(ret, "Get supported authenticators"); + + return (AuthenticatorTransport)supported; + } + + /// + /// Makes a new web authentication credential and stores it to authenticator. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#sctn-createCredential + /// + /// 12 + /// http://tizen.org/privilege/bluetooth + /// http://tizen.org/privilege/internet + /// public + /// + /// http://tizen.org/feature/security.webauthn + /// http://tizen.org/feature/network.bluetooth.le + /// and at least one of the following: + /// http://tizen.org/feature/network.wifi + /// http://tizen.org/feature/network.ethernet + /// http://tizen.org/feature/network.telephony + /// + /// UTF-8 encoded JSON serialization of the client data. + /// Specifies the desired attributes of the to-be-created public key credential. + /// The callback functions to be invoked. + /// The required feature is not supported. + /// Required privilege is missing. + /// Input parameter is invalid. + /// Operation invalid in current state. + /// Canceled by a cancel request. + 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); + + // Create callback wrappers + WrapMcCallbacks(callbacks); + AuthenticatorStorage.SetDataForMakeCredential(clientData, options); + + int ret = Libwebauthn.MakeCredential( + AuthenticatorStorage.WauthnClientData, + AuthenticatorStorage.WauthnPubkeyCredCreationOptions, + _wauthnMcCallbacks); + CheckErrNThrow(ret, "Make Credential"); + } + catch + { + Cleanup(); + throw; + } + } + + /// + /// Gets assertion from the authenticator. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#sctn-getAssertion + /// + /// 12 + /// http://tizen.org/privilege/bluetooth + /// http://tizen.org/privilege/internet + /// public + /// + /// http://tizen.org/feature/security.webauthn + /// http://tizen.org/feature/network.bluetooth.le + /// and at least one of the following: + /// http://tizen.org/feature/network.wifi + /// http://tizen.org/feature/network.ethernet + /// http://tizen.org/feature/network.telephony + /// + /// UTF-8 encoded JSON serialization of the client data. + /// Specifies the desired attributes of the public key credential to discover. + /// The callback functions to be invoked. + /// The required feature is not supported. + /// Required privilege is missing. + /// Input parameter is invalid. + /// Operation invalid in current state. + /// Canceled by a cancel request. + 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); + + // Create callback wrappers + WrapGaCallbacks(callbacks); + AuthenticatorStorage.SetDataForGetAssertion(clientData, options); + + int ret = Libwebauthn.GetAssertion( + AuthenticatorStorage.WauthnClientData, + AuthenticatorStorage.WauthnPubkeyCredRequestOptions, + _wauthnGaCallbacks); + CheckErrNThrow(ret, "Get Assertion"); + } + catch + { + Cleanup(); + throw; + } + } + + /// + /// Stops the previous or call. + /// + /// 12 + /// http://tizen.org/feature/security.webauthn + /// The required feature is not supported. + /// Not allowed in the current context. + public static void Cancel() + { + int ret = Libwebauthn.Cancel(); + CheckErrNThrow(ret, "Cancel operation"); + } + + #endregion + #region Helper methods + + private static void SetApiVersion(int apiVersionNumber) + { + int ret = Libwebauthn.SetApiVersion(apiVersionNumber); + CheckErrNThrow(ret, "Set API version"); + _apiVersionSet = true; + } + private static void WrapMcCallbacks(MakeCredentialCallbacks callbacks) + { + _userData = callbacks.UserData; + + void qrCodeWrapper(string qrContents, IntPtr _) + { + callbacks.QrcodeCallback(qrContents, _userData); + } + + void onResponseWrapper(WauthnPubkeyCredentialAttestation pubkeyCred, WauthnError result, IntPtr _) + { + PubkeyCredAttestation pubkeyCredManaged = pubkeyCred is not null ? new(pubkeyCred) : null; + callbacks.ResponseCallback(pubkeyCredManaged, result, _userData); + + if (result != WauthnError.None) + Cleanup(); + } + + void linkedDataWrapper(IntPtr linkedData, WauthnError result, IntPtr _) + { + HybridLinkedData linkedDataManaged = linkedData != IntPtr.Zero ? new(Marshal.PtrToStructure(linkedData)) : null; + callbacks.LinkedDataCallback(linkedDataManaged, result, _userData); + + if (result != WauthnError.NoneAndWait) + Cleanup(); + } + + _qrCodeCallback = new WauthnDisplayQrcodeCallback(qrCodeWrapper); + _mcResponseCallback = new WauthnMcOnResponseCallback(onResponseWrapper); + _linkedDataCallback = new WauthnUpdateLinkedDataCallback(linkedDataWrapper); + + _wauthnMcCallbacks = new WauthnMcCallbacks(_qrCodeCallback, _mcResponseCallback, _linkedDataCallback); + } + + private static void WrapGaCallbacks(GetAssertionCallbacks callbacks) + { + _userData = callbacks.UserData; + + void qrCodeWrapper(string qrContents, IntPtr _) + { + callbacks.QrcodeCallback(qrContents, _userData); + } + + void onResponseWrapper(WauthnPubkeyCredentialAssertion pubkeyCred, WauthnError result, IntPtr _) + { + PubkeyCredAssertion pubkeyCredManaged = pubkeyCred is not null ? new(pubkeyCred) : null; + callbacks.ResponseCallback(pubkeyCredManaged, result, _userData); + + if (result != WauthnError.None) + Cleanup(); + } + + void linkedDataWrapper(IntPtr linkedData, WauthnError result, IntPtr _) + { + HybridLinkedData linkedDataManaged = linkedData != IntPtr.Zero ? new(Marshal.PtrToStructure(linkedData)) : null; + callbacks.LinkedDataCallback(linkedDataManaged, result, _userData); + + if (result != WauthnError.NoneAndWait) + Cleanup(); + } + _qrCodeCallback = new WauthnDisplayQrcodeCallback(qrCodeWrapper); + _gaResponseCallback = new WauthnGaOnResponseCallback(onResponseWrapper); + _linkedDataCallback = new WauthnUpdateLinkedDataCallback(linkedDataWrapper); + + _wauthnGaCallbacks = new WauthnGaCallbacks(_qrCodeCallback, _gaResponseCallback, _linkedDataCallback); + } + + private static void CheckPreconditions() + { + if (!_apiVersionSet) + SetApiVersion(API_VERSION_NUMBER); + if (_busy) + throw new InvalidOperationException("Authenticator busy"); + + _busy = true; + } + + private static void Cleanup() + { + _busy = false; + AuthenticatorStorage.Cleanup(); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorAssertionResponse.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorAssertionResponse.cs new file mode 100644 index 00000000000..c8bc6723d9f --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorAssertionResponse.cs @@ -0,0 +1,65 @@ +/* + * 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 +{ + /// + /// The response of GetAssertion(). + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#authenticatorassertionresponse + /// + /// 12 + public class AuthenticatorAssertionResponse + { + internal AuthenticatorAssertionResponse(WauthnAuthenticatorAssertionResponse wauthnResponse) + { + ClientDataJson = NullSafeMarshal.PtrToArray(wauthnResponse.clientDataJson); + AuthenticatorData = NullSafeMarshal.PtrToArray(wauthnResponse.attestationObject); + Signature = NullSafeMarshal.PtrToArray(wauthnResponse.signature); + UserHandle = NullSafeMarshal.PtrToArray(wauthnResponse.userHandle); + AttestationObject = NullSafeMarshal.PtrToArray(wauthnResponse.attestationObject); + } + + /// + /// JSON-compatible serialization of client data. + /// + public byte[] ClientDataJson { get; init; } + /// + /// The authenticator data contained within attestation_object. + /// For more information, refer to https://www.w3.org/TR/webauthn-3/#sctn-authenticator-data + /// + public byte[] AuthenticatorData { get; init; } + /// + /// The raw signature returned from the authenticator. + /// For more information, refer to https://www.w3.org/TR/webauthn-3/#sctn-op-get-assertion + /// + public byte[] Signature { get; init; } + /// + /// The user handle returned from the authenticator, + /// or null if the authenticator did not return a user handle. + /// + public byte[] UserHandle { get; init; } + /// + /// This OPTIONAL attribute contains an attestation object, + /// if the authenticator supports attestation in assertions. + /// + public byte[] AttestationObject { get; init; } + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorAttestationResponse.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorAttestationResponse.cs new file mode 100644 index 00000000000..e4209c00f52 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorAttestationResponse.cs @@ -0,0 +1,69 @@ +/* + * 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 +{ + /// + /// The response of MakeCredential(). + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#authenticatorattestationresponse + /// + /// 12 + public class AuthenticatorAttestationResponse + { + internal AuthenticatorAttestationResponse(WauthnAuthenticatorAttestationResponse wauthnResponse) + { + ClientDataJson = NullSafeMarshal.PtrToArray(wauthnResponse.clientDataJson); + AttestationObject = NullSafeMarshal.PtrToArray(wauthnResponse.attestationObject); + Transports = (AuthenticatorTransport)wauthnResponse.transports; + AuthenticatorData = NullSafeMarshal.PtrToArray(wauthnResponse.authenticatorData); + SubjectPubkeyInfo = NullSafeMarshal.PtrToArray(wauthnResponse.subjectPubkeyInfo); + PubkeyAlg = wauthnResponse.pubkeyAlg; + } + + /// + /// JSON-compatible serialization of client data. + /// + public byte[] ClientDataJson { get; init; } + /// + /// The CBOR encoded Attestation Object to be returned to the RP. + /// + public byte[] AttestationObject { get; init; } + /// + /// To represent multiple transports, can be ORed multiple times. + /// + public AuthenticatorTransport Transports { get; init; } + /// + /// The authenticator data contained within attestation_object. + /// For more information, refer to https://www.w3.org/TR/webauthn-3/#sctn-authenticator-data + /// + public byte[] AuthenticatorData { get; init; } + /// + /// DER SubjectPublicKeyInfo of the new credential, or null if this is not available. + /// For more information, refer to https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.7 + /// + public byte[] SubjectPubkeyInfo { get; init; } + /// + /// The COSEAlgorithmIdentifier of the new credential. + /// + public CoseAlgorithm PubkeyAlg { get; init; } + + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorStorage.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorStorage.cs new file mode 100644 index 00000000000..a47c6718f89 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/AuthenticatorStorage.cs @@ -0,0 +1,370 @@ +/* + * 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; +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 + { + #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(); + #endregion + + public static void SetDataForMakeCredential(ClientData clientData, PubkeyCredCreationOptions options) + { + CopyClientData(clientData); + CopyCredCreationOptions(options); + } + + public static void SetDataForGetAssertion(ClientData clientData, PubkeyCredRequestOptions options) + { + CopyClientData(clientData); + CopyCredRequestOptions(options); + } + + public static void Cleanup() + { + CleanupArray(_credentialsIdUnmanagedDataArray); + CleanupArray(_credentialsIdUnmanagedConstBufferArray); + CleanupArray(_attestationFormatsUnmanagedDataArray); + CleanupArray(_attestationFormatsUnmanagedConstBufferArray); + CleanupArray(_extensionIdUnmanagedDataArray); + CleanupArray(_extensionIdUnmanagedConstBufferArray); + CleanupArray(_extensionValueUnmanagedDataArray); + CleanupArray(_extensionValueUnmanagedConstBufferArray); + + _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(); + _attestationFormatsUnmanaged.Dispose(); + _extensionsArrayUnmanaged.Dispose(); + _extensionsUnmanaged.Dispose(); + _contactIdDataUnmanaged.Dispose(); + _contactIdUnmanaged.Dispose(); + _linkIdDataUnmanaged.Dispose(); + _linkIdUnmanaged.Dispose(); + _linkSecretDataUnmanaged.Dispose(); + _linkSecretUnmanaged.Dispose(); + _authenticatorPubkeyDataUnmanaged.Dispose(); + _authenticatorPubkeyUnmanaged.Dispose(); + _authenticatorNameDataUnmanaged.Dispose(); + _authenticatorNameUnmanaged.Dispose(); + _signatureDataUnmanaged.Dispose(); + _signatureUnmanaged.Dispose(); + _tunnelServerDomainDataUnmanaged.Dispose(); + _tunnelServerDomainUnmanaged.Dispose(); + _identityKeyDataUnmanaged.Dispose(); + _identityKeyUnmanaged.Dispose(); + _linkedDeviceUnmanaged.Dispose(); + } + + private static 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 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 credentials) + { + if (credentials is null || !credentials.Any()) + return; + + var credentialsCount = credentials.Count(); + _credentialsIdUnmanagedDataArray = new UnmanagedMemory[credentialsCount]; + _credentialsIdUnmanagedConstBufferArray = new UnmanagedMemory[credentialsCount]; + var credentialsStructArray = new WauthnPubkeyCredDescriptor[credentialsCount]; + + for (int i = 0; i < credentialsCount; i++) + { + PubkeyCredDescriptor descriptor = credentials.ElementAt(i); + _credentialsIdUnmanagedDataArray[i] = UnmanagedMemory.PinArray(descriptor.Id); + var credentialIdUnmanagedConstBuffer = new UnmanagedMemory(new WauthnConstBuffer(_credentialsIdUnmanagedDataArray[i], (nuint)descriptor.Id.Length)); + _credentialsIdUnmanagedConstBufferArray[i] = credentialIdUnmanagedConstBuffer; + credentialsStructArray[i] = new WauthnPubkeyCredDescriptor(descriptor.Type, credentialIdUnmanagedConstBuffer, descriptor.Transport); + } + _credentialsDescriptorsUnmanaged = UnmanagedMemory.PinArray(credentialsStructArray); + _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 hints) + { + if (hints is null || !hints.Any()) + return; + + int[] hintsArray = hints.Select((PubkeyCredHint hint) => (int)hint).ToArray(); + _hintsArrayUnmanaged = UnmanagedMemory.PinArray(hintsArray); + _hintsUnmanaged = new UnmanagedMemory(new WauthnPubkeyCredHints((nuint)hintsArray.Length, _hintsArrayUnmanaged)); + } + + private static void CopyAttestationFormats(IEnumerable attestationFormats) + { + if (attestationFormats is null || !attestationFormats.Any()) + return; + + var attestationFormatsCount = attestationFormats.Count(); + _attestationFormatsUnmanagedDataArray = new UnmanagedMemory[attestationFormatsCount]; + _attestationFormatsUnmanagedConstBufferArray = new UnmanagedMemory[attestationFormatsCount]; + var attestationFormatConstBufferStructArray = new WauthnConstBuffer[attestationFormatsCount]; + + + for (int i = 0; i < attestationFormatsCount; i++) + { + byte[] attestationFormat = attestationFormats.ElementAt(i); + _attestationFormatsUnmanagedDataArray[i] = UnmanagedMemory.PinArray(attestationFormat); + attestationFormatConstBufferStructArray[i] = new WauthnConstBuffer(_attestationFormatsUnmanagedDataArray[i], (nuint)attestationFormat.Length); + _attestationFormatsUnmanagedConstBufferArray[i] = new UnmanagedMemory(attestationFormatConstBufferStructArray[i]); + } + _attestationFormatsArrayUnmanaged = UnmanagedMemory.PinArray(attestationFormatConstBufferStructArray); + _attestationFormatsUnmanaged = new UnmanagedMemory(new WauthnAttestationFormats((nuint)attestationFormatsCount, _attestationFormatsArrayUnmanaged)); + } + + private static void CopyExtensions(IEnumerable extensions) + { + if (extensions is null || !extensions.Any()) + return; + + var extensionCount = extensions.Count(); + var extensionStructArray = new WauthnAuthenticationExt[extensionCount]; + _extensionIdUnmanagedDataArray = new UnmanagedMemory[extensionCount]; + _extensionIdUnmanagedConstBufferArray = new UnmanagedMemory[extensionCount]; + _extensionValueUnmanagedDataArray = new UnmanagedMemory[extensionCount]; + _extensionValueUnmanagedConstBufferArray = new UnmanagedMemory[extensionCount]; + + for (int i = 0; i < extensionCount; i++) + { + AuthenticationExtension ext = extensions.ElementAt(i); + _extensionIdUnmanagedDataArray[i] = UnmanagedMemory.PinArray(ext.ExtensionId); + var extensionIdUnmanagedConstBuffer = new UnmanagedMemory(new WauthnConstBuffer(_extensionIdUnmanagedDataArray[i], (nuint)ext.ExtensionId.Length)); + _extensionIdUnmanagedConstBufferArray[i] = extensionIdUnmanagedConstBuffer; + + _extensionValueUnmanagedDataArray[i] = UnmanagedMemory.PinArray(ext.ExtensionValue); + var extensionValueUnmanagedConstBuffer = new UnmanagedMemory(new WauthnConstBuffer(_extensionValueUnmanagedDataArray[i], (nuint)ext.ExtensionValue.Length)); + _extensionValueUnmanagedConstBufferArray[i] = extensionValueUnmanagedConstBuffer; + + extensionStructArray[i] = new WauthnAuthenticationExt(extensionIdUnmanagedConstBuffer, extensionValueUnmanagedConstBuffer); + } + _extensionsArrayUnmanaged = UnmanagedMemory.PinArray(extensionStructArray); + _extensionsUnmanaged = new UnmanagedMemory(new WauthnAuthenticationExts((nuint)extensionCount, _extensionsArrayUnmanaged)); + } + + private static void CopyLinkedDevice(HybridLinkedData linkedDevice) + { + if (linkedDevice is null) + return; + + _contactIdDataUnmanaged = UnmanagedMemory.PinArray(linkedDevice.ContactId); + _contactIdUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_contactIdDataUnmanaged, (nuint)linkedDevice.ContactId.Length)); + + _linkIdDataUnmanaged = UnmanagedMemory.PinArray(linkedDevice.LinkId); + _linkIdUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_linkIdDataUnmanaged, (nuint)linkedDevice.LinkId.Length)); + + _linkSecretDataUnmanaged = UnmanagedMemory.PinArray(linkedDevice.LinkSecret); + _linkSecretUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_linkSecretDataUnmanaged, (nuint)linkedDevice.LinkSecret.Length)); + + _authenticatorPubkeyDataUnmanaged = UnmanagedMemory.PinArray(linkedDevice.AuthenticatorPubkey); + _authenticatorPubkeyUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_authenticatorPubkeyDataUnmanaged, (nuint)linkedDevice.AuthenticatorPubkey.Length)); + + _authenticatorNameDataUnmanaged = UnmanagedMemory.PinArray(linkedDevice.AuthenticatorName); + _authenticatorNameUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_authenticatorNameDataUnmanaged, (nuint)linkedDevice.AuthenticatorName.Length)); + + _signatureDataUnmanaged = UnmanagedMemory.PinArray(linkedDevice.Signature); + _signatureUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_signatureDataUnmanaged, (nuint)linkedDevice.Signature.Length)); + + _tunnelServerDomainDataUnmanaged = UnmanagedMemory.PinArray(linkedDevice.TunnelServerDomain); + _tunnelServerDomainUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_tunnelServerDomainDataUnmanaged, (nuint)linkedDevice.TunnelServerDomain.Length)); + + _identityKeyDataUnmanaged = UnmanagedMemory.PinArray(linkedDevice.IdentityKey); + _identityKeyUnmanaged = new UnmanagedMemory(new WauthnConstBuffer(_identityKeyDataUnmanaged, (nuint)linkedDevice.IdentityKey.Length)); + + _linkedDeviceUnmanaged = new UnmanagedMemory(new WauthnHybridLinkedData( + _contactIdUnmanaged, + _linkIdUnmanaged, + _linkSecretUnmanaged, + _authenticatorPubkeyUnmanaged, + _authenticatorNameUnmanaged, + _signatureUnmanaged, + _tunnelServerDomainUnmanaged, + _identityKeyUnmanaged)); + + if (_linkedDeviceUnmanaged == IntPtr.Zero) + throw new TimeoutException("linked null"); + } + + public static void CleanupArray(UnmanagedMemory[] array) + { + if (array is null) + return; + foreach (var memory in array) + memory.Dispose(); + } + + public static WauthnClientData WauthnClientData { get; private set; } + public static WauthnPubkeyCredCreationOptions WauthnPubkeyCredCreationOptions { get; private set; } + public static WauthnPubkeyCredRequestOptions WauthnPubkeyCredRequestOptions { get; private set; } + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/ClientData.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/ClientData.cs new file mode 100644 index 00000000000..609cfb4e749 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/ClientData.cs @@ -0,0 +1,52 @@ +/* + * 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 Tizen.Security.WebAuthn.ErrorFactory; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Client data JSON. + /// + /// + /// Refer to the following W3C specification about how to encode jsonData. + /// https://www.w3.org/TR/webauthn-3/#collectedclientdata-json-compatible-serialization-of-client-data + /// + /// 12 + public class ClientData + { + /// + /// Initializes a new instance of the class. + /// + /// 12 + /// UTF-8 encoded JSON serialization of the client data. + /// Hash algorithm used to hash the JsonData property. + public ClientData(byte[] jsonData, HashAlgorithm hashAlgo) + { + JsonData = jsonData; + HashAlgo = hashAlgo; + } + + /// + /// UTF-8 encoded JSON serialization of the client data. + /// + public byte[] JsonData { get; init; } + /// + /// Hash algorithm used to hash the JsonData property. + /// + public HashAlgorithm HashAlgo{ get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AttestationPref.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AttestationPref.cs new file mode 100644 index 00000000000..72e82da87be --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AttestationPref.cs @@ -0,0 +1,46 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn attestation preference. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#enumdef-attestationconveyancepreference + /// + /// 12 + public enum AttestationPref + { + /// + /// Relying party not interested in authenticator attestation. + /// + None = 0, + /// + /// Indirect attestation preferred. + /// + Indirect = 1, + /// + /// Direct attestation preferred. + /// + Direct = 2, + /// + /// Enterprise attestation preferred. + /// + Enterprise = 3, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AuthenticatorAttachment.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AuthenticatorAttachment.cs new file mode 100644 index 00000000000..ca0b6d85a07 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AuthenticatorAttachment.cs @@ -0,0 +1,42 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn authentication attachment value. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#enumdef-authenticatorattachment + /// + /// 12 + public enum AuthenticatorAttachment + { + /// + /// No attachment. + /// + None = 0, + /// + /// Platform attachment. + /// + Platform = 1, + /// + /// Cross-platform attachment. + /// + CrossPlatform = 2, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AuthenticatorTransport.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AuthenticatorTransport.cs new file mode 100644 index 00000000000..1204281e79b --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/AuthenticatorTransport.cs @@ -0,0 +1,62 @@ +/* + * 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; + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn authenticator transports. + /// + /// + /// Multiple transport values can be combined using bit-wise operation. + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#enum-transport + /// + /// 12 + [Flags] + public enum AuthenticatorTransport : uint + { + /// + /// No transport specified. + /// + None = 0x00000000, + /// + /// Authenticator reachable over USB. + /// + Usb = 0x00000001, + /// + /// Authenticator reachable over NFC. + /// + Nfc = 0x00000002, + /// + /// Authenticator reachable over BLE. + /// + Ble = 0x00000004, + /// + /// Authenticator reachable using Smart Card. + /// + Smartcard = 0x00000008, + /// + /// Authenticator reachable using a combination of mechanisms. + /// + Hybrid = 0x00000010, + /// + /// Authenticator reachable using a client device-specific transport. + /// + Internal = 0x00000020, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/CoseAlgorithm.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/CoseAlgorithm.cs new file mode 100644 index 00000000000..cf88cde620d --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/CoseAlgorithm.cs @@ -0,0 +1,70 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn COSE (CBOR Object Signing and Encryption) algorithms. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#sctn-alg-identifier + /// + /// 12 + public enum CoseAlgorithm + { + /// + /// ES256 + /// + EcdsaP256WithSha256 = -7, + /// + /// ES384 + /// + EcdsaP384WithSha384 = -35, + /// + /// ES512 + /// + EcdsaP521WithSha512 = -36, + /// + /// EdDSA + /// + Eddsa = -8, + /// + /// PS256 + /// + RsaPssWithSha256 = -37, + /// + /// PS384 + /// + RsaPssWithSha384 = -38, + /// + /// PS512 + /// + RsaPssWithSha512 = -39, + /// + /// RS256 + /// + RsaSsaPkcs1V1_5WithSha256 = -257, + /// + /// RS384 + /// + RsaSsaPkcs1V1_5WithSha384 = -258, + /// + /// RS512 + /// + RsaSsaPkcs1V1_5WithSha512 = -259, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/HashAlogithm.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/HashAlogithm.cs new file mode 100644 index 00000000000..1ca2a480726 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/HashAlogithm.cs @@ -0,0 +1,35 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn hash algorithms. + /// Currently one hash algorithm is used, namely "SHA-256". + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#collectedclientdata-hash-of-the-serialized-client-data + /// + /// 12 + public enum HashAlgorithm + { + /// + /// SHA-256 + /// + Sha256 = 1, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/PubkeyCredHint.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/PubkeyCredHint.cs new file mode 100644 index 00000000000..cc09494f162 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/PubkeyCredHint.cs @@ -0,0 +1,46 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn public key credential hint value. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#enumdef-publickeycredentialhints + /// + /// 12 + public enum PubkeyCredHint + { + /// + /// None. + /// + None = 0, + /// + /// Physical security key. + /// + SecurityKey = 1, + /// + /// Platform authenticator attached to a client device. + /// + ClientDevice = 2, + /// + /// General-purpose authenticator. + /// + Hybrid = 3, // Hybrid + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/PubkeyCredType.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/PubkeyCredType.cs new file mode 100644 index 00000000000..6a4207a46d5 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/PubkeyCredType.cs @@ -0,0 +1,35 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn credential type. + /// Currently one credential type is defined, namely "public-key". + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#enumdef-publickeycredentialtype + /// + /// 12 + public enum PubkeyCredType + { + /// + /// Public-key. + /// + PublicKey = 1, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/ResidentKeyRequirement.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/ResidentKeyRequirement.cs new file mode 100644 index 00000000000..8def5ff56bf --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/ResidentKeyRequirement.cs @@ -0,0 +1,46 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn resident key requirement value. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#enum-residentKeyRequirement + /// + /// 12 + public enum ResidentKeyRequirement + { + /// + /// None. + /// + None = 0, + /// + /// Resident key discouraged. + /// + Discouraged = 1, + /// + /// Resident key preferred. + /// + Preferred = 2, + /// + /// Resident key required. + /// + Required = 3, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/UserVerificationRequirement.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/UserVerificationRequirement.cs new file mode 100644 index 00000000000..9052bd771da --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/UserVerificationRequirement.cs @@ -0,0 +1,46 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn user verification requirement value. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#enumdef-userverificationrequirement + /// + /// 12 + public enum UserVerificationRequirement + { + /// + /// None. + /// + None = 0, + /// + /// User verification required. + /// + Required = 1, + /// + /// User verification preferred. + /// + Preferred = 2, + /// + /// User verification discouraged. + /// + Discouraged = 3, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/WauthnError.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/WauthnError.cs new file mode 100644 index 00000000000..abd7e816349 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/Enums/WauthnError.cs @@ -0,0 +1,92 @@ +/* + * 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 Tizen.Internals.Errors; +using static Tizen.Security.WebAuthn.ErrorFactory; + +namespace Tizen.Security.WebAuthn +{ + /// + /// WebAuthn error code. + /// + public enum WauthnError + { + /// + /// Successful. + /// + None = ErrorCode.None, + /// + /// Unknown error. + /// + Unknown = ErrorCode.Unknown, + /// + /// Invalid function parameter. + /// + InvalidParameter = ErrorCode.InvalidParameter, + /// + /// Permission denied. + /// + PermissionDenied = ErrorCode.PermissionDenied, + /// + /// Not supported operation. + /// + NotSupported = ErrorCode.NotSupported, + /// + /// Memory error. + /// + OutOfMemory = ErrorCode.OutOfMemory, + /// + /// Canceled by cancel request. + /// + Canceled = ErrorCode.Canceled, + /// + /// Timeout. + /// + TimedOut = ErrorCode.TimedOut, + /// + /// Authenticator is uncontactable. + /// + ConnectionRefused = ErrorCode.ConnectionRefused, + /// + /// Successful and needs to wait for other result. + /// + NoneAndWait = TizenErrorWebAuthn | 0x01, + /// + /// Not allowed in the current context. + /// + NotAllowed = TizenErrorWebAuthn | 0x02, + /// + /// Invalid State. + /// + InvalidState = TizenErrorWebAuthn | 0x03, + /// + /// Encoding operation failed. + /// + EncodingFailed = TizenErrorWebAuthn | 0x04, + /// + /// Socket error. + /// + Socket = TizenErrorWebAuthn | 0x05, + /// + /// Socket operation on non-socket error. + /// + NoSuchDevice = TizenErrorWebAuthn | 0x06, + /// + /// Socket access denied. + /// + AccessDenied = TizenErrorWebAuthn | 0x07, + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/ErrorFactory.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/ErrorFactory.cs new file mode 100644 index 00000000000..0015d130d9c --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/ErrorFactory.cs @@ -0,0 +1,58 @@ +/* + * 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; +using System.Runtime.CompilerServices; +using Tizen.Internals.Errors; + +namespace Tizen.Security.WebAuthn +{ + internal static class ErrorFactory + { + internal const int TizenErrorWebAuthn = -0x03100000; + private const string LogTag = "Tizen.Security.WebAuthn"; + + internal static void CheckErrNThrow(int err, string msg) + { + string fullMessage = $"[{LogTag}] {msg}, error={ErrorFacts.GetErrorMessage(err)}"; + + switch (err) + { + case (int)WauthnError.None: + return; + case (int)WauthnError.InvalidParameter: + throw new ArgumentException(fullMessage); + case (int)WauthnError.PermissionDenied: + throw new UnauthorizedAccessException(fullMessage); + case (int)WauthnError.NotSupported: + throw new NotSupportedException(fullMessage); + case (int)WauthnError.Canceled: + throw new OperationCanceledException(fullMessage); + case (int)WauthnError.TimedOut: + throw new TimeoutException(fullMessage); + default: + throw new InvalidOperationException(fullMessage); + } + } + + internal static void CheckNullNThrow(object obj, [CallerArgumentExpression("obj")] string name = null) + { + if (obj is null) + throw new ArgumentNullException(name); + } + } +} + diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/GetAssertionCallbacks.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/GetAssertionCallbacks.cs new file mode 100644 index 00000000000..b3a79daa60b --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/GetAssertionCallbacks.cs @@ -0,0 +1,101 @@ +/* + * 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; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Callback function list used to get assertion with . + /// + /// 12 + public class GetAssertionCallbacks + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Provided callbacks MUST NOT THROW. + /// + /// 12 + /// + /// Callback function for displaying QR code. + /// The qr_contents are encoded as you can see in the encodeQRContents() function of the + /// FIDO specification: + /// https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#hybrid-qr-initiated. + /// The qr_contents is encoded like "FIDO:/0254318383..........7406596245". + /// The image to be displayed shall be created from qr_contents + /// with media vision API (). + /// If the request does not need to display a QR code + /// then this callback function won't be invoked. + /// + /// + /// Callback function for getting the final response. + /// Invoked when the response for the GetAssertion request need to be returned. + /// The result of the GetAssertion request may be one of the following: + /// * if the request is completed well, + /// * if the request is cancelled by a Cancel() request. + /// * if the server entered invalid state. Known causes: + /// - proxy issues, + /// - reached the limit of credentials stored by the authenticator. + /// * if the request times out. Known causes: + /// - authenticator does not respond during state assisted transactions due to + /// lack of push notifications support (e.g. missing Google Account). + /// + /// + /// Callback function for getting the updated linked device data. May be called multiple times. + /// Invoked when the response for the request + /// needs to be returned. The result of this request may be one of the following: + /// * if the request is completed well, + /// * if the request is cancelled by a Cancel() request. + /// * if the server entered invalid state. Known causes: + /// - proxy issues, + /// - reached the limit of credentials stored by the authenticator. + /// * if the request times out. Known causes: + /// - authenticator does not respond during state assisted transactions due to + /// lack of push notifications support (e.g. missing Google Account). + /// + /// User data to be passed to , and . + public GetAssertionCallbacks( + Action qrcodeCallback, + Action responseCallback, + Action linkedDataCallback, + object userData) + { + QrcodeCallback = qrcodeCallback; + ResponseCallback = responseCallback; + LinkedDataCallback = linkedDataCallback; + UserData = userData; + } + + /// + /// Callback function for displaying QR code. + /// + public Action QrcodeCallback { get; init; } + /// + /// Callback function for getting the final response. + /// + public Action ResponseCallback { get; init; } + /// + /// Callback function for getting the updated linked device data. + /// + public Action LinkedDataCallback { get; init; } + /// + /// User data to be passed to , and . + /// + public object UserData { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/HybridLinkedData.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/HybridLinkedData.cs new file mode 100644 index 00000000000..f12d8852cc0 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/HybridLinkedData.cs @@ -0,0 +1,124 @@ +/* + * 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; +using static Tizen.Security.WebAuthn.ErrorFactory; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Linked device data. + /// + /// + /// The linked device data is used for state assisted transaction. + /// From the successful QR initiated transaction, the linked device data + /// might be returned from an authenticator to a webauthn client + /// via or . + /// Then the client can store the linked device data and use it in the next call + /// for or . + /// Then the stated assisted transaction will start instead of QR initiated transaction. + /// + /// For more information, find a section with the keyword, "linking map", + /// from the following specification. + /// https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html + /// + /// For more information about state assisted transaction, refer to the following. + /// https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#hybrid-state-assisted + /// + /// 12 + public class HybridLinkedData + { + /// + /// Initializes a new instance of the class. + /// + /// + /// More information on the CBOR format can be found in the following specification: + /// https://www.rfc-editor.org/rfc/rfc8949.html + /// + /// CBOR:"1". + /// CBOR:"2". + /// CBOR:"3". + /// CBOR:"4". + /// CBOR:"5". + /// CBOR:"6". + /// Domain String of tunnel server. + /// Identity Key created during QR initiated transaction. + public HybridLinkedData( + byte[] contactId, + byte[] linkId, + byte[] linkSecret, + byte[] authenticatorPubkey, + byte[] authenticatorName, + byte[] signature, + byte[] tunnelServerDomain, + byte[] identityKey) + { + ContactId = contactId; + LinkId = linkId; + LinkSecret = linkSecret; + AuthenticatorPubkey = authenticatorPubkey; + AuthenticatorName = authenticatorName; + Signature = signature; + TunnelServerDomain = tunnelServerDomain; + IdentityKey = identityKey; + } + + internal HybridLinkedData(WauthnHybridLinkedData linkedData) + { + ContactId = NullSafeMarshal.PtrToArray(linkedData.contactId); + LinkId = NullSafeMarshal.PtrToArray(linkedData.linkId); + LinkSecret = NullSafeMarshal.PtrToArray(linkedData.linkSecret); + AuthenticatorPubkey = NullSafeMarshal.PtrToArray(linkedData.authenticatorPubkey); + AuthenticatorName = NullSafeMarshal.PtrToArray(linkedData.authenticatorName); + Signature = NullSafeMarshal.PtrToArray(linkedData.signature); + TunnelServerDomain = NullSafeMarshal.PtrToArray(linkedData.tunnelServerDomain); + IdentityKey = NullSafeMarshal.PtrToArray(linkedData.identityKey); + } + + /// + /// CBOR:"1". + /// + public byte[] ContactId { get; init; } + /// + /// CBOR:"3". + /// + public byte[] LinkId { get; init; } + /// + /// CBOR:"3". + /// + public byte[] LinkSecret { get; init; } + /// + /// CBOR:"4". + /// + public byte[] AuthenticatorPubkey { get; init; } + /// + /// CBOR:"5". + /// + public byte[] AuthenticatorName { get; init; } + /// + /// CBOR:"6". + /// + public byte[] Signature { get; init; } + /// + /// Domain String of tunnel server. + /// + public byte[] TunnelServerDomain { get; init; } + /// + /// Identity Key created during QR initiated transaction. + /// + public byte[] IdentityKey { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/MakeCredentialCallbacks.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/MakeCredentialCallbacks.cs new file mode 100644 index 00000000000..9d3ecf19485 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/MakeCredentialCallbacks.cs @@ -0,0 +1,101 @@ +/* + * 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; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Callback function list used to make credential with . + /// + /// 12 + public class MakeCredentialCallbacks + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Provided callbacks MUST NOT THROW. + /// + /// 12 + /// + /// Callback function for displaying QR code. + /// The qr_contents are encoded as you can see in the encodeQRContents() function of the + /// FIDO specification: + /// https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#hybrid-qr-initiated. + /// The qr_contents is encoded like "FIDO:/0254318383..........7406596245". + /// The image to be displayed shall be created from qr_contents + /// with media vision API (). + /// If the request does not need to display a QR code + /// then this callback function won't be invoked. + /// + /// + /// Callback function for getting the final response. + /// Invoked when the response for the request + /// needs to be returned. The result of this request may be one of the following: + /// * if the request is completed well, + /// * if the request is cancelled by a Cancel() request. + /// * if the server entered invalid state. Known causes: + /// - proxy issues, + /// - reached the limit of credentials stored by the authenticator. + /// * if the request times out. Known causes: + /// - authenticator does not respond during state assisted transactions due to + /// lack of push notifications support (e.g. missing Google Account). + /// + /// + /// Callback function for getting the updated linked device data. May be called multiple times. + /// Invoked when the response for the get assertion request needs to be returned. + /// The result of the MakeCredential request may be one of the following: + /// * if the request is completed well, + /// * if the request is cancelled by a Cancel() request. + /// * if the server entered invalid state. Known causes: + /// - proxy issues, + /// - reached the limit of credentials stored by the authenticator. + /// * if the request times out. Known causes: + /// - authenticator does not respond during state assisted transactions due to + /// lack of push notifications support (e.g. missing Google Account). + /// + /// User data to be passed to , and . + public MakeCredentialCallbacks( + Action qrcodeCallback, + Action responseCallback, + Action linkedDataCallback, + object userData) + { + QrcodeCallback = qrcodeCallback; + ResponseCallback = responseCallback; + LinkedDataCallback = linkedDataCallback; + UserData = userData; + } + + /// + /// Callback function for displaying QR code. + /// + public Action QrcodeCallback { get; init; } + /// + /// Callback function for getting the final response. + /// + public Action ResponseCallback { get; init; } + /// + /// Callback function for getting the updated linked device data. + /// + public Action LinkedDataCallback { get; init; } + /// + /// User data to be passed to , and . + /// + public object UserData { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/NullSafeMarshal.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/NullSafeMarshal.cs new file mode 100644 index 00000000000..36dc2f6d90e --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/NullSafeMarshal.cs @@ -0,0 +1,34 @@ +/* + * 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; +using System.Runtime.InteropServices; +using static Interop; + +namespace Tizen.Security.WebAuthn +{ + internal static class NullSafeMarshal + { + internal static byte[] PtrToArray(IntPtr ptr) + { + if (ptr == IntPtr.Zero) + return null; + + return Marshal.PtrToStructure(ptr).ToArray(); + } + } +} + diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredAssertion.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredAssertion.cs new file mode 100644 index 00000000000..292a30e66a0 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredAssertion.cs @@ -0,0 +1,102 @@ +/* + * 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; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using static Interop; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Public key credential response for . + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#iface-pkcredential + /// https://www.w3.org/TR/webauthn-3/#sctn-credentialrequestoptions-extension + /// + /// 12 + public class PubkeyCredAssertion + { + internal PubkeyCredAssertion(WauthnPubkeyCredentialAssertion assertion) + { + Id = NullSafeMarshal.PtrToArray(assertion.id); + Type = assertion.type; + RawId = NullSafeMarshal.PtrToArray(assertion.rawId); + Response = assertion.response != IntPtr.Zero ? new AuthenticatorAssertionResponse( + Marshal.PtrToStructure(assertion.response)) : + null; + AuthenticatorAttachment = assertion.authenticatorAttachment; + + if (assertion.extensions != IntPtr.Zero) + { + var wauthnExts = Marshal.PtrToStructure(assertion.extensions); + var extensionsArray = new AuthenticationExtension[wauthnExts.size]; + unsafe + { + var extPtr = (WauthnAuthenticationExt*)wauthnExts.descriptors; + for (int i = 0; i < (int)wauthnExts.size; i++) + { + var wauthnExt = Marshal.PtrToStructure(new IntPtr(extPtr + i * sizeof(WauthnAuthenticationExt))); + extensionsArray[i] = new AuthenticationExtension(wauthnExt); + } + } + Extensions = extensionsArray; + } + else + { + Extensions = null; + } + + LinkedDevice = assertion.linkedDevice != IntPtr.Zero ? + new HybridLinkedData(Marshal.PtrToStructure(assertion.linkedDevice)) : + null; + } + + /// + /// The base64url encoding of credential’s identifier. + /// + public byte[] Id { get; init; } + /// + /// The credential’s type. + /// + public PubkeyCredType Type { get; init; } + /// + /// The raw value of credential’s identifier. + /// + public byte[] RawId { get; init; } + /// + /// Authenticator's response. + /// + public AuthenticatorAssertionResponse Response { get; init; } + /// + /// Authenticator attachment modality. + /// + public AuthenticatorAttachment AuthenticatorAttachment { get; init; } + /// + /// The results of processing client extensions requested by the Relying Party + /// upon the Relying Party's invocation of GetAssertion(). (optional) + /// + public IEnumerable Extensions { get; init; } + /// + /// Linked Device Connection Info (optional). + /// If not null, the caller has to store this value and use this + /// in the next transaction to invoke state assisted transaction. + /// + public HybridLinkedData LinkedDevice { get; init; } + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredAttestation.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredAttestation.cs new file mode 100644 index 00000000000..12368be29f2 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredAttestation.cs @@ -0,0 +1,102 @@ +/* + * 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; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using static Interop; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Public key credential response for . + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#iface-pkcredential + /// https://www.w3.org/TR/webauthn-3/#sctn-credentialcreationoptions-extension + /// + /// 12 + public class PubkeyCredAttestation + { + internal PubkeyCredAttestation(WauthnPubkeyCredentialAttestation attestation) + { + Id = NullSafeMarshal.PtrToArray(attestation.id); + Type = attestation.type; + RawId = NullSafeMarshal.PtrToArray(attestation.rawId); + Response = attestation.response != IntPtr.Zero ? + new AuthenticatorAttestationResponse(Marshal.PtrToStructure(attestation.response)) : + null; + AuthenticatorAttachment = attestation.authenticatorAttachment; + + if (attestation.extensions != IntPtr.Zero) + { + var wauthnExts = Marshal.PtrToStructure(attestation.extensions); + var extensionsArray = new AuthenticationExtension[wauthnExts.size]; + unsafe + { + var extPtr = (WauthnAuthenticationExt*)wauthnExts.descriptors; + for (int i = 0; i < (int)wauthnExts.size; i++) + { + var wauthnExt = Marshal.PtrToStructure(new IntPtr(extPtr + i * sizeof(WauthnAuthenticationExt))); + extensionsArray[i] = new AuthenticationExtension(wauthnExt); + } + } + Extensions = extensionsArray; + } + else + { + Extensions = null; + } + + LinkedDevice = attestation.linkedDevice != IntPtr.Zero ? + new HybridLinkedData(Marshal.PtrToStructure(attestation.linkedDevice)) : + null; + } + + /// + /// The base64url encoding of credential’s identifier. + /// + public byte[] Id { get; init; } + /// + /// The credential’s type. + /// + public PubkeyCredType Type { get; init; } + /// + /// The raw value of credential’s identifier. + /// + public byte[] RawId { get; init; } + /// + /// Authenticator's response. + /// + public AuthenticatorAttestationResponse Response { get; init; } + /// + /// Authenticator attachment modality. + /// + public AuthenticatorAttachment AuthenticatorAttachment { get; init; } + /// + /// The results of processing client extensions requested by the Relying Party + /// upon the Relying Party's invocation of MakeCredential(). (optional) + /// + public IEnumerable Extensions { get; init; } + /// + /// Linked Device Connection Info (optional). + /// If not null, the caller has to store this value and use thi + /// in the next transaction to invoke state assisted transaction. + /// + public HybridLinkedData LinkedDevice { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredCreationOptions.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredCreationOptions.cs new file mode 100644 index 00000000000..9f812041609 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredCreationOptions.cs @@ -0,0 +1,153 @@ +/* + * 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 static Tizen.Security.WebAuthn.ErrorFactory; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Make credential options. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialcreationoptions + /// + /// 12 + public class PubkeyCredCreationOptions + { + /// + /// Initializes a new instance of the class. + /// + /// /// 12 + /// Contains a name and an identifier for the Relying Party responsible for the request. + /// Contains names and an identifier for the user account performing the registration. + /// + /// Lists the key types and signature algorithms the Relying Party supports, + /// ordered from most preferred to least preferred. + /// + /// + /// Specifies a time, in milliseconds, + /// that the Relying Party is willing to wait for the call to complete. + /// This is treated as a hint, and MAY be overridden by the client. + /// The value, '0', means no timeout is set. (optional) + /// + /// + /// The Relying Party SHOULD use this argument to list any existing credentials mapped + /// to this user account (as identified by user.id). (optional) + /// + /// + /// The Relying Party MAY use his argument to specify capabilities and settings that the + /// authenticator MUST or SHOULD satisfy to participate in this operation. (optional) + /// + /// + /// Contains zero or more elements from to + /// guide the user agent in interacting with the user. (optional) + /// + /// + /// The Relying Party MAY use this argument to specify a preference regarding attestation conveyance. + /// The default value is . (optional) + /// + /// + /// The Relying Party MAY use this argument to specify a preference regarding the attestation + /// statement format used by the authenticator. The default value is the empty list, which + /// indicates no preference. (optional) + /// + /// + /// The Relying Party MAY use this argument to provide client extension inputs requesting + /// additional processing by the client and authenticator. (optional) + /// + /// + /// Linked Device Connection Info. Optional. + /// If not null, the state assisted transaction will start. + /// + public PubkeyCredCreationOptions( + RelyingPartyEntity rp, + UserEntity user, + IEnumerable pubkeyCredParams, + ulong timeout = 0, + IEnumerable excludeCredentials = null, + AuthenticationSelectionCriteria authenticatorSelection = null, + IEnumerable hints = null, + AttestationPref attestation = AttestationPref.None, + IEnumerable attestationFormats = null, + IEnumerable extensions = null, + HybridLinkedData linkedDevice = null) + { + Rp = rp; + User = user; + PubkeyCredParams = pubkeyCredParams; + Timeout = timeout; + ExcludeCredentials = excludeCredentials; + AuthenticatorSelection = authenticatorSelection; + Hints = hints; + Attestation = attestation; + AttestationFormats = attestationFormats; + Extensions = extensions; + LinkedDevice = linkedDevice; + } + + /// + /// Contains a name and an identifier for the Relying Party responsible for the request. + /// + public RelyingPartyEntity Rp { get; init; } + /// + /// Contains names and an identifier for the user account performing the registration. + /// + public UserEntity User { get; init; } + /// + /// Lists the key types and signature algorithms the Relying Party supports, + /// ordered from most preferred to least preferred. + /// + public IEnumerable PubkeyCredParams { get; init; } + /// + /// Specifies a time, in milliseconds, that the Relying Party is willing to wait for the + /// call to complete. This is treated as a hint, and MAY be overridden by the client. + /// The value, '0', means no timeout is set. + /// + public ulong Timeout { get; init; } + /// + /// Lists any existing credentials mapped to this user account (as identified by user.id). + /// + public IEnumerable ExcludeCredentials { get; init; } + /// + /// Specifies capabilities and settings that the authenticator MUST or SHOULD satisfy + /// to participate in this operation. + /// + public AuthenticationSelectionCriteria AuthenticatorSelection { get; init; } + /// + /// Contains zero or more elements from to + /// guide the user agent in interacting with the user. + /// + public IEnumerable Hints { get; init; } + /// + /// Specifies a preference regarding attestation conveyance. + /// + public AttestationPref Attestation { get; init; } + /// + /// Specifies a preference regarding the attestation statement format used by the authenticator. + /// + public IEnumerable AttestationFormats { get; init; } + /// + /// Client extension inputs requesting additional processing by the client and authenticator. + /// + public IEnumerable Extensions { get; init; } + /// + /// Linked Device Connection Info. If not null, the state assisted transaction will start. + /// + public HybridLinkedData LinkedDevice { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredDescriptor.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredDescriptor.cs new file mode 100644 index 00000000000..f1a6523318b --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredDescriptor.cs @@ -0,0 +1,56 @@ +/* + * 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 Tizen.Security.WebAuthn.ErrorFactory; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Public key credential descriptor. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialdescriptor + /// + /// 12 + public class PubkeyCredDescriptor + { + /// + /// Initializes a new instance of the class. + /// + /// The type of the public key credential. + /// The credential ID of the public key credential. + /// To represent multiple transports, this enum can be ORed multiple times. + public PubkeyCredDescriptor(PubkeyCredType type, byte[] id, AuthenticatorTransport transport) + { + Type = type; + Id = id; + Transport = transport; + } + /// + /// The type of the public key credential. + /// + public PubkeyCredType Type { get; init; } + /// + /// The credential ID of the public key credential. + /// + public byte[] Id { get; init; } + /// + /// Transport types. + /// + public AuthenticatorTransport Transport { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredParam.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredParam.cs new file mode 100644 index 00000000000..762b1195b55 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredParam.cs @@ -0,0 +1,49 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// Parameter for credential generation. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialparameters + /// + /// 12 + public class PubkeyCredParam + { + /// + /// Initializes a new instance of the class. + /// + /// 12 + /// Well-known credential type specifying a credential to create. + /// Well-known COSE algorithm specifying the algorithm to use for the credential. + public PubkeyCredParam(PubkeyCredType type, CoseAlgorithm alg) + { + Type = type; + Alg = alg; + } + /// + /// Well-known credential type specifying a credential to create. + /// + public PubkeyCredType Type { get; init; } + /// + /// Well-known COSE algorithm specifying the algorithm to use for the credential. + /// + public CoseAlgorithm Alg { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredRequestOptions.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredRequestOptions.cs new file mode 100644 index 00000000000..3df50f33ae0 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/PubkeyCredRequestOptions.cs @@ -0,0 +1,133 @@ +/* + * 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; + +namespace Tizen.Security.WebAuthn +{ + /// + /// Get assertion options. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#dictionary-assertion-options + /// + /// 12 + public class PubkeyCredRequestOptions + { + /// + /// Initializes a new instance of the class. + /// + /// 12 + /// + /// Specifies a time, in milliseconds, that the Relying Party is willing to wait for the + /// call to complete. This is treated as a hint, and MAY be overridden by the client. + /// The value, '0', means no timeout is set. (optional) + /// + /// + /// Specifies the RP ID claimed by the Relying Party. (optional) + /// + /// + /// Used by the client to find authenticators eligible for this authentication ceremony. (optional) + /// + /// + /// Specifies the Relying Party's requirements regarding user verification for the + /// GetAssertion() operation. The default value is . (optional) + /// + /// + /// Contains zero or more elements from to + /// guide the user agent in interacting with the user. (optional) + /// + /// + /// The Relying Party MAY use this argument to specify a preference regarding + /// attestation conveyance. The default value is . (optional) + /// + /// + /// The Relying Party MAY use this argument to specify a preference regarding the attestation + /// statement format used by the authenticator. The default value is the empty list, + /// which indicates no preference. (optional) + /// + /// + /// The Relying Party MAY use this argument to provide client extension inputs requesting + /// additional processing by the client and authenticator. (optional) + /// + /// + /// Linked Device Connection Info. Optional. + /// If not null, the state assisted transaction will start. + /// + public PubkeyCredRequestOptions( + ulong timeout = 0, + string rpId = null, + IEnumerable allowCredentials = null, + UserVerificationRequirement userVerification = UserVerificationRequirement.Preferred, + IEnumerable hints = null, + AttestationPref attestation = AttestationPref.None, + IEnumerable attestationFormats = null, + IEnumerable extensions = null, + HybridLinkedData linkedDevice = null) + { + Timeout = timeout; + RpId = rpId; + AllowCredentials = allowCredentials; + UserVerification = userVerification; + Hints = hints; + Attestation = attestation; + AttestationFormats = attestationFormats; + Extensions = extensions; + LinkedDevice = linkedDevice; + } + + /// + /// Specifies a time, in milliseconds, that the Relying Party is willing to wait for the + /// call to complete. This is treated as a hint, and MAY be overridden by the client. + /// The value, '0', means no timeout is set. + /// + public ulong Timeout { get; init; } + /// + /// Specifies the RP ID claimed by the Relying Party. + /// + public string RpId { get; init; } + /// + /// Used by the client to find authenticators eligible for this authentication ceremony. + /// + public IEnumerable AllowCredentials { get; init; } + /// + /// Specifies the Relying Party's requirements regarding user verification for the GetAssertion() operation. + /// + public UserVerificationRequirement UserVerification { get; init; } + /// + /// Contains zero or more elements from to + /// guide the user agent in interacting with the user. + /// + public IEnumerable Hints { get; init; } + /// + /// Specifies a preference regarding attestation conveyance. + /// + public AttestationPref Attestation { get; init; } + /// + /// Specifies a preference regarding the attestation statement format used by the authenticator. + /// + public IEnumerable AttestationFormats { get; init; } + /// + /// Client extension inputs requesting additional processing by the client and authenticator. + /// + public IEnumerable Extensions { get; init; } + /// + /// Linked Device Connection Info. If not null, the state assisted transaction will start. + /// + public HybridLinkedData LinkedDevice { get; init; } + } +} \ No newline at end of file diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/RelyingPartyEntity.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/RelyingPartyEntity.cs new file mode 100644 index 00000000000..f00fdec4fc6 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/RelyingPartyEntity.cs @@ -0,0 +1,50 @@ +/* + * 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 + */ + +namespace Tizen.Security.WebAuthn +{ + /// + /// Relying Party entity. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialrpentity + /// + /// 12 + public class RelyingPartyEntity + { + /// + /// Initializes a new instance of the class. + /// + /// 12 + /// The name of RP. + /// The RPID. + public RelyingPartyEntity(string name, string id) + { + Name = name; + Id = id; + } + + /// + /// The name of RP. + /// + public string Name { get; init; } + /// + /// The RPID. + /// + public string Id { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/UnmanagedMemory.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/UnmanagedMemory.cs new file mode 100644 index 00000000000..2ada7c055f6 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/UnmanagedMemory.cs @@ -0,0 +1,86 @@ +/* + * 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; +using System.Runtime.InteropServices; + +namespace Tizen.Security.WebAuthn +{ + internal class UnmanagedMemory : IDisposable + { + private bool _disposed = false; + IntPtr _memory = IntPtr.Zero; + + public UnmanagedMemory() + {} + + public UnmanagedMemory(object obj) + { + _memory = Marshal.AllocHGlobal(Marshal.SizeOf(obj)); + Marshal.StructureToPtr(obj, _memory, false); + } + + + public UnmanagedMemory(string obj) + { + _memory = Marshal.StringToHGlobalAnsi(obj); + } + + unsafe private UnmanagedMemory(IntPtr pinned, int size) + { + _memory = Marshal.AllocHGlobal(size); + Buffer.MemoryCopy((void*)pinned, (void*)_memory, size, size); + } + + ~UnmanagedMemory() + { + Dispose(false); + } + + public static UnmanagedMemory PinArray(T[] array) where T : struct + { + if (array is null) + return new UnmanagedMemory(); + + GCHandle pinnedArray = GCHandle.Alloc(array, GCHandleType.Pinned); + var ret = new UnmanagedMemory(pinnedArray.AddrOfPinnedObject(), Marshal.SizeOf(array[0]) * array.Length); + pinnedArray.Free(); + return ret; + } + + public static implicit operator IntPtr(UnmanagedMemory pinned) + { + return pinned._memory; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + if (_memory != IntPtr.Zero) + Marshal.FreeHGlobal(_memory); + + _memory = IntPtr.Zero; + _disposed = true; + } + } +} diff --git a/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/UserEntity.cs b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/UserEntity.cs new file mode 100644 index 00000000000..6eb65e12145 --- /dev/null +++ b/src/Tizen.Security.WebAuthn/Tizen.Security.WebAuthn/UserEntity.cs @@ -0,0 +1,61 @@ +/* + * 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 Tizen.Security.WebAuthn.ErrorFactory; + +namespace Tizen.Security.WebAuthn +{ + /// + /// User entity. + /// + /// + /// Refer to the following W3C specification for more information. + /// https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialuserentity + /// + /// 12 + public class UserEntity + { + /// + /// Initializes a new instance of the class. + /// + /// 12 + /// A human-palatable name for the entity. + /// + /// The ID of the user account. An ID is a byte sequence with a maximum size of 64 bytes, + /// and is not meant to be displayed to the user. + /// + /// A human-palatable name for the user account, intended only for display. + public UserEntity(string name, byte[] id, string displayName) + { + Name = name; + Id = id; + DisplayName = displayName; + } + + /// + /// A human-palatable name for the entity. + /// + public string Name { get; init; } + /// + /// The ID of the user account. + /// + public byte[] Id { get; init; } + /// + /// A human-palatable name for the user account, intended only for display. + /// + public string DisplayName { get; init; } + } +} diff --git a/src/Tizen.Security.WebAuthn/doc/api/Tizen.Security.WebAuthn.md b/src/Tizen.Security.WebAuthn/doc/api/Tizen.Security.WebAuthn.md new file mode 100644 index 00000000000..1a66141c89b --- /dev/null +++ b/src/Tizen.Security.WebAuthn/doc/api/Tizen.Security.WebAuthn.md @@ -0,0 +1,21 @@ +--- +uid: Tizen.Security.WebAuthn +summary: The Web Authentication module provides a C# API enabling the creation and use of + strong, attested, scoped, public key-based credentials by web applications, for the + purpose of strongly authenticating users +remarks: *content +--- +## Overview +It provides an [Authenticator](xref:Tizen.Security.WebAuthn.Authenticator) class containing methods for creating public key-based credentials +([Authenticator.MakeCredential()](xref:Tizen.Security.WebAuthn.Authenticator.MakeCredential(Tizen.Security.WebAuthn.ClientData,Tizen.Security.WebAuthn.PubkeyCredCreationOptions,Tizen.Security.WebAuthn.MakeCredentialCallbacks))) and using them ([Authenticator.GetAssertion()](xref:Tizen.Security.WebAuthn.Authenticator.GetAssertion(Tizen.Security.WebAuthn.ClientData,Tizen.Security.WebAuthn.PubkeyCredRequestOptions,Tizen.Security.WebAuthn.GetAssertionCallbacks))). Both these operations are performed asynchronously. Callbacks passed as arguments are used to notify about the progress +or when user's interaction is necessary. Due to significant amount of time required to complete both +requests, cancelation is also possible with the help of Authenticator.Cancel(). The module also +provides a variety of data types based on W3C Web Authentication API (https://www.w3.org/TR/webauthn-3/) +used to control the credential creation and assertion process. + +## Related features +This module is related with the following features: + * http://tizen.org/feature/security.webauthn + * http://tizen.org/feature/network.bluetooth.le + * and network connection features (http://tizen.org/feature/network.wifi, http://tizen.org/feature/network.ethernet, http://tizen.org/feature/network.telephony) +