1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-10 04:23:21 +00:00

[PM-5731] Create C# WebAuthn authenticator to support maui apps (#2951)

* [PM-5731] feat: implement get assertion params object

* [PM-5731] feat: add first test

* [PM-5731] feat: add rp mismatch test

* [PM-5731] feat: ask for credentials when found

* [PM-5731] feat: find discoverable credentials

* [PM-5731] feat: add tests for successful UV requests

* [PM-5731] feat: add user does not consent test

* [PM-5731] feat: check for UV when reprompt is active

* [PM-5731] fix: tests a bit, needed some additional "arrange" steps

* [PM-5731] feat: add support for counter

* [PM-5731] feat: implement assertion without signature

* [PM-5732] feat: finish authenticator assertion implementation

note: CryptoFunctionService still needs Sign implemenation

* [PM-5731] chore: minor clean up

* [PM-5731] feat: scaffold make credential

* [PM-5731] feat: start implementing attestation

* [PM-5731] feat: implement credential exclusion

* [PM-5731] feat: add new credential confirmaiton

* [PM-5731] feat: implement credential creation

* [PM-5731] feat: add user verification checks

* [PM-5731] feat: add unknown error handling

* [PM-5731] chore: clean up unusued params

* [PM-5731] feat: partial attestation implementation

* [PM-5731] feat: implement key generation

* [PM-5731] feat: return public key in DER format

* [PM-5731] feat: implement signing

* [PM-5731] feat: remove logging

* [PM-5731] chore: use primary constructor

* [PM-5731] chore: add Async to method names

* [PM-5731] feat: add support for silent discoverability

* [PM-5731] feat: add support for specifying user presence requirement

* [PM-5731] feat: ensure unlocked vault

* [PM-5731] chore: clean up and refactor assertion tests

* [PM-5731] chore: clean up and refactor attestation tests

* [PM-5731] chore: add user presence todo comment

* [PM-5731] feat: scaffold fido2 client

* PM-5731 Fix build updating discoverable flag

* [PM-5731] fix: failing test

* [PM-5731] feat: add sameOriginWithAncestor and user id length checks

* [PM-5731] feat: add incomplete rpId verification

* [PM-5731] chore: document uri helpers

* [PM-5731] feat: implement fido2 client createCredential

* [PM-5731] feat: implement credential assertion in client

* fix wrong signature format

(cherry picked from commit a1c9ebf01f)

* [PM-5731] fix: issues after cherry-pick

* Fix incompatible GUID conversions

(cherry picked from commit c801b2fc3a)

* [PM-5731] chore: remove default constructor

* [PM-5731] feat: refactor user interface to increase flexibility

* [PM-5731] feat: implement generic assertion user interface class

* [PM-5731] feat: remove ability to make user presence optional

* [PM-5731] chore: remove logging comments

* [PM-5731] feat: add native reprompt support to the authenticator

* [PM-5731] feat: allow pre and post UV

* [PM-5731] chore: add `Async` to method name. Remove `I` from struct

* [PM-5731] fix: discoverable string repr lowercase

* [PM-5731] chore: don't use C# 12 features

* [PM-5731] fix: replace magic strings and numbers with contants and enums

* [PM-5731] fix: use UTC creation date

* [PM-5731] fix: formatting

* [PM-5731] chore: use properties for public fields

* [PM-5731] chore: remove TODO

* [PM-5731] fix: IsValidRpId

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
Co-authored-by: mpbw2 <59324545+mpbw2@users.noreply.github.com>
This commit is contained in:
Andreas Coroiu
2024-02-21 16:12:52 +01:00
committed by GitHub
parent d339514d9a
commit 71de3bedf4
45 changed files with 3166 additions and 21 deletions

View File

@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models.Domain;
namespace Bit.Core.Abstractions
{

View File

@@ -0,0 +1,12 @@
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
public interface IFido2AuthenticatorService
{
Task<Fido2AuthenticatorMakeCredentialResult> MakeCredentialAsync(Fido2AuthenticatorMakeCredentialParams makeCredentialParams, IFido2MakeCredentialUserInterface userInterface);
Task<Fido2AuthenticatorGetAssertionResult> GetAssertionAsync(Fido2AuthenticatorGetAssertionParams assertionParams, IFido2GetAssertionUserInterface userInterface);
// TODO: Should this return a List? Or maybe IEnumerable?
Task<Fido2AuthenticatorDiscoverableCredentialMetadata[]> SilentCredentialDiscoveryAsync(string rpId);
}
}

View File

@@ -0,0 +1,35 @@
using Bit.Core.Utilities.Fido2;
namespace Bit.Core.Abstractions
{
/// <summary>
/// This class represents an abstraction of the WebAuthn Client as described by W3C:
/// https://www.w3.org/TR/webauthn-3/#webauthn-client
///
/// The WebAuthn Client is an intermediary entity typically implemented in the user agent
/// (in whole, or in part). Conceptually, it underlies the Web Authentication API and embodies
/// the implementation of the Web Authentication API's operations.
///
/// It is responsible for both marshalling the inputs for the underlying authenticator operations,
/// and for returning the results of the latter operations to the Web Authentication API's callers.
/// </summary>
public interface IFido2ClientService
{
/// <summary>
/// Allows WebAuthn Relying Party scripts to request the creation of a new public key credential source.
/// For more information please see: https://www.w3.org/TR/webauthn-3/#sctn-createCredential
/// </summary>
/// <param name="createCredentialParams">The parameters for the credential creation operation</param>
/// <returns>The new credential</returns>
Task<Fido2ClientCreateCredentialResult> CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams);
/// <summary>
/// Allows WebAuthn Relying Party scripts to discover and use an existing public key credential, with the users consent.
/// Relying Party script can optionally specify some criteria to indicate what credential sources are acceptable to it.
/// For more information please see: https://www.w3.org/TR/webauthn-3/#sctn-getAssertion
/// </summary>
/// <param name="assertCredentialParams">The parameters for the credential assertion operation</param>
/// <returns>The asserted credential</returns>
Task<Fido2ClientAssertCredentialResult> AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams);
}
}

View File

@@ -0,0 +1,18 @@
namespace Bit.Core.Abstractions
{
public struct Fido2GetAssertionUserInterfaceCredential
{
public string CipherId { get; set; }
public bool RequireUserVerification { get; set; }
}
public interface IFido2GetAssertionUserInterface : IFido2UserInterface
{
/// <summary>
/// Ask the user to pick a credential from a list of existing credentials.
/// </summary>
/// <param name="credentials">The credentials that the user can pick from, and if the user must be verified before completing the operation</param>
/// <returns>The ID of the cipher that contains the credentials the user picked, and if the user was verified before completing the operation</returns>
Task<(string CipherId, bool UserVerified)> PickCredentialAsync(Fido2GetAssertionUserInterfaceCredential[] credentials);
}
}

View File

@@ -0,0 +1,37 @@
namespace Bit.Core.Abstractions
{
public struct Fido2ConfirmNewCredentialParams
{
///<summary>
/// The name of the credential.
///</summary>
public string CredentialName { get; set; }
///<summary>
/// The name of the user.
///</summary>
public string UserName { get; set; }
/// <summary>
/// Whether or not the user must be verified before completing the operation.
/// </summary>
public bool UserVerification { get; set; }
}
public interface IFido2MakeCredentialUserInterface : IFido2UserInterface
{
/// <summary>
/// Inform the user that the operation was cancelled because their vault contains excluded credentials.
/// </summary>
/// <param name="existingCipherIds">The IDs of the excluded credentials.</param>
/// <returns>When user has confirmed the message</returns>
Task InformExcludedCredentialAsync(string[] existingCipherIds);
/// <summary>
/// Ask the user to confirm the creation of a new credential.
/// </summary>
/// <param name="confirmNewCredentialParams">The parameters to use when asking the user to confirm the creation of a new credential.</param>
/// <returns>The ID of the cipher where the new credential should be saved, and if the user was verified before completing the operation</returns>
Task<(string CipherId, bool UserVerified)> ConfirmNewCredentialAsync(Fido2ConfirmNewCredentialParams confirmNewCredentialParams);
}
}

View File

@@ -0,0 +1,12 @@
namespace Bit.Core.Abstractions
{
public interface IFido2UserInterface
{
/// <summary>
/// Make sure that the vault is unlocked.
/// This should open a window and ask the user to login or unlock the vault if necessary.
/// </summary>
/// <returns>When vault has been unlocked.</returns>
Task EnsureUnlockedVaultAsync();
}
}