diff --git a/src/App/Platforms/Android/Autofill/CredentialHelpers.cs b/src/App/Platforms/Android/Autofill/CredentialHelpers.cs index 616ca0f22..7e3f1feda 100644 --- a/src/App/Platforms/Android/Autofill/CredentialHelpers.cs +++ b/src/App/Platforms/Android/Autofill/CredentialHelpers.cs @@ -7,9 +7,11 @@ using AndroidX.Credentials.Exceptions; using AndroidX.Credentials.Provider; using AndroidX.Credentials.WebAuthn; using Bit.App.Abstractions; +using Bit.App.Droid.Utilities; using Bit.Core.Abstractions; using Bit.Core.Resources.Localization; using Bit.Core.Utilities; +using Bit.Core.Utilities.Fido2; using Bit.Core.Utilities.Fido2.Extensions; using Bit.Droid; using Org.Json; @@ -65,7 +67,7 @@ namespace Bit.App.Platforms.Android.Autofill var request = new PublicKeyCredentialCreationOptions(json); var jsonObj = new JSONObject(json); var authenticatorSelection = jsonObj.GetJSONObject("authenticatorSelection"); - request.AuthenticatorSelection = new AuthenticatorSelectionCriteria( + request.AuthenticatorSelection = new AndroidX.Credentials.WebAuthn.AuthenticatorSelectionCriteria( authenticatorSelection.OptString("authenticatorAttachment", "platform"), authenticatorSelection.OptString("residentKey", null), authenticatorSelection.OptBoolean("requireResidentKey", false), @@ -77,14 +79,23 @@ namespace Bit.App.Platforms.Android.Autofill public static async Task CreateCipherPasskeyAsync(ProviderCreateCredentialRequest getRequest, Activity activity) { var callingRequest = getRequest?.CallingRequest as CreatePublicKeyCredentialRequest; + + if (callingRequest is null) + { + if (ServiceContainer.TryResolve(out var deviceActionService)) + { + await deviceActionService.DisplayAlertAsync(AppResources.ErrorCreatingPasskey, string.Empty, AppResources.Ok); + } + FailAndFinish(); + return; + } + var origin = callingRequest.Origin; var credentialCreationOptions = GetPublicKeyCredentialCreationOptionsFromJson(callingRequest.RequestJson); - if (origin is null - && - ServiceContainer.TryResolve(out var deviceActionService)) + if (origin is null) { - await deviceActionService.DisplayAlertAsync(AppResources.ErrorCreatingPasskey, AppResources.PasskeysNotSupportedForThisApp, AppResources.Ok); + origin = getRequest.CallingAppInfo?.GetAndroidOrigin(); } var rp = new Core.Utilities.Fido2.PublicKeyCredentialRpEntity() @@ -121,7 +132,7 @@ namespace Bit.App.Platforms.Android.Autofill var timeout = Convert.ToInt32(credentialCreationOptions.Timeout); - var credentialCreateParams = new Bit.Core.Utilities.Fido2.Fido2ClientCreateCredentialParams() + var credentialCreateParams = new Fido2ClientCreateCredentialParams() { Challenge = credentialCreationOptions.GetChallenge(), Origin = origin, @@ -136,14 +147,17 @@ namespace Bit.App.Platforms.Android.Autofill SameOriginWithAncestors = true }; + var credentialExtraCreateParams = new Fido2ExtraCreateCredentialParams + ( + callingRequest.GetClientDataHash(), + getRequest.CallingAppInfo?.PackageName + ); + var fido2MediatorService = ServiceContainer.Resolve(); - var clientCreateCredentialResult = await fido2MediatorService.CreateCredentialAsync(credentialCreateParams); + var clientCreateCredentialResult = await fido2MediatorService.CreateCredentialAsync(credentialCreateParams, credentialExtraCreateParams); if (clientCreateCredentialResult == null) { - var resultErrorIntent = new Intent(); - PendingIntentHandler.SetCreateCredentialException(resultErrorIntent, new CreateCredentialUnknownException()); - activity.SetResult(Result.Ok, resultErrorIntent); - activity.Finish(); + FailAndFinish(); return; } @@ -157,7 +171,10 @@ namespace Bit.App.Platforms.Android.Autofill } var responseInnerAndroidJson = new JSONObject(); - responseInnerAndroidJson.Put("clientDataJSON", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.ClientDataJSON)); + if (clientCreateCredentialResult.ClientDataJSON != null) + { + responseInnerAndroidJson.Put("clientDataJSON", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.ClientDataJSON)); + } responseInnerAndroidJson.Put("authenticatorData", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.AuthData)); responseInnerAndroidJson.Put("attestationObject", CoreHelpers.Base64UrlEncode(clientCreateCredentialResult.AttestationObject)); responseInnerAndroidJson.Put("transports", transportsArray); @@ -172,16 +189,21 @@ namespace Bit.App.Platforms.Android.Autofill rootAndroidJson.Put("clientExtensionResults", MapExtensionsToJson(clientCreateCredentialResult.Extensions)); rootAndroidJson.Put("response", responseInnerAndroidJson); - var responseAndroidJson = rootAndroidJson.ToString(); - - System.Diagnostics.Debug.WriteLine(responseAndroidJson); - var result = new Intent(); - var publicKeyResponse = new CreatePublicKeyCredentialResponse(responseAndroidJson); + var publicKeyResponse = new CreatePublicKeyCredentialResponse(rootAndroidJson.ToString()); PendingIntentHandler.SetCreateCredentialResponse(result, publicKeyResponse); activity.SetResult(Result.Ok, result); activity.Finish(); + + void FailAndFinish() + { + var result = new Intent(); + PendingIntentHandler.SetCreateCredentialException(result, new CreateCredentialUnknownException()); + + activity.SetResult(Result.Ok, result); + activity.Finish(); + } } private static Fido2CreateCredentialExtensionsParams MapExtensionsFromJson(PublicKeyCredentialCreationOptions options) diff --git a/src/App/Platforms/Android/Autofill/CredentialProviderSelectionActivity.cs b/src/App/Platforms/Android/Autofill/CredentialProviderSelectionActivity.cs index 8c09b2e49..d229327d8 100644 --- a/src/App/Platforms/Android/Autofill/CredentialProviderSelectionActivity.cs +++ b/src/App/Platforms/Android/Autofill/CredentialProviderSelectionActivity.cs @@ -5,15 +5,16 @@ using Android.OS; using AndroidX.Credentials; using AndroidX.Credentials.Provider; using AndroidX.Credentials.WebAuthn; +using Bit.App.Droid.Utilities; using Bit.App.Abstractions; using Bit.Core.Abstractions; using Bit.Core.Utilities; -using Bit.App.Droid.Utilities; using Bit.Core.Resources.Localization; using Bit.Core.Utilities.Fido2; -using Java.Security; using Bit.Core.Services; using Bit.App.Platforms.Android.Autofill; +using AndroidX.Credentials.Exceptions; +using Org.Json; namespace Bit.Droid.Autofill { @@ -58,7 +59,13 @@ namespace Bit.Droid.Autofill { var getRequest = PendingIntentHandler.RetrieveProviderGetCredentialRequest(Intent); - var credentialOption = getRequest?.CredentialOptions.FirstOrDefault(); + if (getRequest is null) + { + FailAndFinish(); + return; + } + + var credentialOption = getRequest.CredentialOptions.FirstOrDefault(); var credentialPublic = credentialOption as GetPublicKeyCredentialOption; var requestOptions = new PublicKeyCredentialRequestOptions(credentialPublic.RequestJson); @@ -68,14 +75,14 @@ namespace Bit.Droid.Autofill var credentialId = requestInfo?.GetByteArray(CredentialProviderConstants.CredentialIdIntentExtra); var hasVaultBeenUnlockedInThisTransaction = Intent.GetBooleanExtra(CredentialProviderConstants.CredentialHasVaultBeenUnlockedInThisTransactionExtra, false); - var androidOrigin = AppInfoToOrigin(getRequest?.CallingAppInfo); - var packageName = getRequest?.CallingAppInfo.PackageName; - var appInfoOrigin = getRequest?.CallingAppInfo.Origin; + var androidOrigin = getRequest.CallingAppInfo.GetAndroidOrigin(); + var packageName = getRequest.CallingAppInfo.PackageName; + var origin = getRequest.CallingAppInfo.Origin ?? androidOrigin; - if (appInfoOrigin is null) + if (origin is null) { await _deviceActionService.Value.DisplayAlertAsync(AppResources.ErrorReadingPasskey, AppResources.PasskeysNotSupportedForThisApp, AppResources.Ok); - Finish(); + FailAndFinish(); return; } @@ -91,31 +98,41 @@ namespace Bit.Droid.Autofill Challenge = requestOptions.GetChallenge(), RpId = RpId, AllowCredentials = new Core.Utilities.Fido2.PublicKeyCredentialDescriptor[] { new Core.Utilities.Fido2.PublicKeyCredentialDescriptor { Id = credentialId } }, - Origin = appInfoOrigin, + Origin = origin, SameOriginWithAncestors = true, UserVerification = requestOptions.UserVerification }; - var assertResult = await _fido2MediatorService.Value.AssertCredentialAsync(clientAssertParams, credentialPublic.GetClientDataHash()); - - var response = new AuthenticatorAssertionResponse( - requestOptions, - assertResult.SelectedCredential.Id, - androidOrigin, - false, // These flags have no effect, we set our own within `SetAuthenticatorData` - false, - false, - false, - assertResult.SelectedCredential.UserHandle, - packageName, - assertResult.ClientDataHash + var extraAssertParams = new Fido2ExtraAssertCredentialParams + ( + getRequest.CallingAppInfo.Origin != null ? credentialPublic.GetClientDataHash() : null, + packageName ); - response.SetAuthenticatorData(assertResult.AuthenticatorData); - response.SetSignature(assertResult.Signature); + + var assertResult = await _fido2MediatorService.Value.AssertCredentialAsync(clientAssertParams, extraAssertParams); var result = new Intent(); - var fidoCredential = new FidoPublicKeyCredential(assertResult.SelectedCredential.Id, response, "platform"); - var cred = new PublicKeyCredential(fidoCredential.Json()); + + var responseInnerAndroidJson = new JSONObject(); + if (assertResult.ClientDataJSON != null) + { + responseInnerAndroidJson.Put("clientDataJSON", CoreHelpers.Base64UrlEncode(assertResult.ClientDataJSON)); + } + responseInnerAndroidJson.Put("authenticatorData", CoreHelpers.Base64UrlEncode(assertResult.AuthenticatorData)); + responseInnerAndroidJson.Put("signature", CoreHelpers.Base64UrlEncode(assertResult.Signature)); + responseInnerAndroidJson.Put("userHandle", CoreHelpers.Base64UrlEncode(assertResult.SelectedCredential.UserHandle)); + + var rootAndroidJson = new JSONObject(); + rootAndroidJson.Put("id", CoreHelpers.Base64UrlEncode(assertResult.SelectedCredential.Id)); + rootAndroidJson.Put("rawId", CoreHelpers.Base64UrlEncode(assertResult.SelectedCredential.Id)); + rootAndroidJson.Put("authenticatorAttachment", "platform"); + rootAndroidJson.Put("type", "public-key"); + rootAndroidJson.Put("clientExtensionResults", new JSONObject()); + rootAndroidJson.Put("response", responseInnerAndroidJson); + + var json = rootAndroidJson.ToString(); + + var cred = new PublicKeyCredential(json); var credResponse = new GetCredentialResponse(cred); PendingIntentHandler.SetGetCredentialResponse(result, credResponse); @@ -130,7 +147,7 @@ namespace Bit.Droid.Autofill await MainThread.InvokeOnMainThreadAsync(async () => { await _deviceActionService.Value.DisplayAlertAsync(AppResources.ErrorReadingPasskey, string.Format(AppResources.ThereWasAProblemReadingAPasskeyForXTryAgainLater, RpId), AppResources.Ok); - Finish(); + FailAndFinish(); }); } catch (Exception ex) @@ -139,17 +156,18 @@ namespace Bit.Droid.Autofill await MainThread.InvokeOnMainThreadAsync(async () => { await _deviceActionService.Value.DisplayAlertAsync(AppResources.ErrorReadingPasskey, string.Format(AppResources.ThereWasAProblemReadingAPasskeyForXTryAgainLater, RpId), AppResources.Ok); - Finish(); + FailAndFinish(); }); } } - private string AppInfoToOrigin(CallingAppInfo info) + private void FailAndFinish() { - var cert = info.SigningInfo.GetApkContentsSigners()[0].ToByteArray(); - var md = MessageDigest.GetInstance("SHA-256"); - var certHash = md.Digest(cert); - return $"android:apk-key-hash:${CoreHelpers.Base64UrlEncode(certHash)}"; + var result = new Intent(); + PendingIntentHandler.SetGetCredentialException(result, new GetCredentialUnknownException()); + + SetResult(Result.Ok, result); + Finish(); } } } diff --git a/src/App/Platforms/Android/Utilities/CallingAppInfoExtensions.cs b/src/App/Platforms/Android/Utilities/CallingAppInfoExtensions.cs new file mode 100644 index 000000000..27de6cb38 --- /dev/null +++ b/src/App/Platforms/Android/Utilities/CallingAppInfoExtensions.cs @@ -0,0 +1,23 @@ +using Android.OS; +using AndroidX.Credentials.Provider; +using Bit.Core.Utilities; +using Java.Security; + +namespace Bit.App.Droid.Utilities +{ + public static class CallingAppInfoExtensions + { + public static string GetAndroidOrigin(this CallingAppInfo callingAppInfo) + { + if (Build.VERSION.SdkInt < BuildVersionCodes.P || callingAppInfo?.SigningInfo?.GetApkContentsSigners().Any() != true) + { + return null; + } + + var cert = callingAppInfo.SigningInfo.GetApkContentsSigners()[0].ToByteArray(); + var md = MessageDigest.GetInstance("SHA-256"); + var certHash = md.Digest(cert); + return $"android:apk-key-hash:{CoreHelpers.Base64UrlEncode(certHash)}"; + } + } +} diff --git a/src/Core/Abstractions/IFido2ClientService.cs b/src/Core/Abstractions/IFido2ClientService.cs index d3ca04dd9..8684ff4e1 100644 --- a/src/Core/Abstractions/IFido2ClientService.cs +++ b/src/Core/Abstractions/IFido2ClientService.cs @@ -20,8 +20,9 @@ namespace Bit.Core.Abstractions /// For more information please see: https://www.w3.org/TR/webauthn-3/#sctn-createCredential /// /// The parameters for the credential creation operation + /// Extra parameters for the credential creation operation /// The new credential - Task CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, byte[] clientDataHash); + Task CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, Fido2ExtraCreateCredentialParams extraParams); /// /// Allows WebAuthn Relying Party scripts to discover and use an existing public key credential, with the user’s consent. @@ -29,7 +30,8 @@ namespace Bit.Core.Abstractions /// For more information please see: https://www.w3.org/TR/webauthn-3/#sctn-getAssertion /// /// The parameters for the credential assertion operation + /// Extra parameters for the credential assertion operation /// The asserted credential - Task AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, byte[] clientDataHash); + Task AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, Fido2ExtraAssertCredentialParams extraParams); } } diff --git a/src/Core/Abstractions/IFido2MediatorService.cs b/src/Core/Abstractions/IFido2MediatorService.cs index 7464f5423..a177d1e80 100644 --- a/src/Core/Abstractions/IFido2MediatorService.cs +++ b/src/Core/Abstractions/IFido2MediatorService.cs @@ -4,8 +4,8 @@ namespace Bit.Core.Abstractions { public interface IFido2MediatorService { - Task CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, byte[] clientDataHash = null); - Task AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, byte[] clientDataHash = null); + Task CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, Fido2ExtraCreateCredentialParams extraParams); + Task AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, Fido2ExtraAssertCredentialParams extraParams); Task MakeCredentialAsync(Fido2AuthenticatorMakeCredentialParams makeCredentialParams, IFido2MakeCredentialUserInterface userInterface); Task GetAssertionAsync(Fido2AuthenticatorGetAssertionParams assertionParams, IFido2GetAssertionUserInterface userInterface); diff --git a/src/Core/Services/Fido2ClientService.cs b/src/Core/Services/Fido2ClientService.cs index bf8be680b..65c9bc778 100644 --- a/src/Core/Services/Fido2ClientService.cs +++ b/src/Core/Services/Fido2ClientService.cs @@ -1,5 +1,6 @@ using System.Text; using System.Text.Json; +using System.Text.Json.Nodes; using Bit.Core.Abstractions; using Bit.Core.Enums; using Bit.Core.Utilities; @@ -33,7 +34,7 @@ namespace Bit.Core.Services _makeCredentialUserInterface = makeCredentialUserInterface; } - public async Task CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, byte[] clientDataHash = null) + public async Task CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, Fido2ExtraCreateCredentialParams extraParams) { var blockedUris = await _stateService.GetAutofillBlacklistedUrisAsync(); var domain = CoreHelpers.GetHostname(createCredentialParams.Origin); @@ -72,14 +73,15 @@ namespace Bit.Core.Services "The length of user.id is not between 1 and 64 bytes (inclusive)"); } - if (!createCredentialParams.Origin.StartsWith("https://")) + var isAndroidOrigin = createCredentialParams.Origin.StartsWith("android:apk-key-hash"); + if (!isAndroidOrigin && !createCredentialParams.Origin.StartsWith("https://")) { throw new Fido2ClientException( Fido2ClientException.ErrorCode.SecurityError, "Origin is not a valid https origin"); } - if (!Fido2DomainUtils.IsValidRpId(createCredentialParams.Rp.Id, createCredentialParams.Origin)) + if (!isAndroidOrigin && !Fido2DomainUtils.IsValidRpId(createCredentialParams.Rp.Id, createCredentialParams.Origin)) { throw new Fido2ClientException( Fido2ClientException.ErrorCode.SecurityError, @@ -110,17 +112,23 @@ namespace Bit.Core.Services } byte[] clientDataJSONBytes = null; + var clientDataHash = extraParams.ClientDataHash; if (clientDataHash == null) { - var clientDataJSON = JsonSerializer.Serialize(new + var clientDataJsonObject = new JsonObject { - type = "webauthn.create", - challenge = CoreHelpers.Base64UrlEncode(createCredentialParams.Challenge), - origin = createCredentialParams.Origin, - crossOrigin = !createCredentialParams.SameOriginWithAncestors, + { "type", "webauthn.create" }, + { "challenge", CoreHelpers.Base64UrlEncode(createCredentialParams.Challenge) }, + { "origin", createCredentialParams.Origin }, + { "crossOrigin", !createCredentialParams.SameOriginWithAncestors } // tokenBinding: {} // Not supported - }); - clientDataJSONBytes = Encoding.UTF8.GetBytes(clientDataJSON); + }; + if (!string.IsNullOrWhiteSpace(extraParams.AndroidPackageName)) + { + clientDataJsonObject.Add("androidPackageName", extraParams.AndroidPackageName); + } + + clientDataJSONBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(clientDataJsonObject)); clientDataHash = await _cryptoFunctionService.HashAsync(clientDataJSONBytes, CryptoHashAlgorithm.Sha256); } var makeCredentialParams = MapToMakeCredentialParams(createCredentialParams, credTypesAndPubKeyAlgs, clientDataHash); @@ -163,7 +171,7 @@ namespace Bit.Core.Services } } - public async Task AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, byte[] clientDataHash = null) + public async Task AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, Fido2ExtraAssertCredentialParams extraParams) { var blockedUris = await _stateService.GetAutofillBlacklistedUrisAsync(); var domain = CoreHelpers.GetHostname(assertCredentialParams.Origin); @@ -188,14 +196,15 @@ namespace Bit.Core.Services "Saving Bitwarden credentials in a Bitwarden vault is not allowed"); } - if (!assertCredentialParams.Origin.StartsWith("https://")) + var isAndroidOrigin = assertCredentialParams.Origin.StartsWith("android:apk-key-hash"); + if (!isAndroidOrigin && !assertCredentialParams.Origin.StartsWith("https://")) { throw new Fido2ClientException( Fido2ClientException.ErrorCode.SecurityError, "Origin is not a valid https origin"); } - if (!Fido2DomainUtils.IsValidRpId(assertCredentialParams.RpId, assertCredentialParams.Origin)) + if (!isAndroidOrigin && !Fido2DomainUtils.IsValidRpId(assertCredentialParams.RpId, assertCredentialParams.Origin)) { throw new Fido2ClientException( Fido2ClientException.ErrorCode.SecurityError, @@ -203,16 +212,23 @@ namespace Bit.Core.Services } byte[] clientDataJSONBytes = null; + var clientDataHash = extraParams.ClientDataHash; if (clientDataHash == null) { - var clientDataJSON = JsonSerializer.Serialize(new + var clientDataJsonObject = new JsonObject { - type = "webauthn.get", - challenge = CoreHelpers.Base64UrlEncode(assertCredentialParams.Challenge), - origin = assertCredentialParams.Origin, - crossOrigin = !assertCredentialParams.SameOriginWithAncestors, - }); - clientDataJSONBytes = Encoding.UTF8.GetBytes(clientDataJSON); + { "type", "webauthn.get" }, + { "challenge", CoreHelpers.Base64UrlEncode(assertCredentialParams.Challenge) }, + { "origin", assertCredentialParams.Origin }, + { "crossOrigin", !assertCredentialParams.SameOriginWithAncestors } + // tokenBinding: {} // Not supported + }; + if (!string.IsNullOrWhiteSpace(extraParams.AndroidPackageName)) + { + clientDataJsonObject.Add("androidPackageName", extraParams.AndroidPackageName); + } + + clientDataJSONBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(clientDataJsonObject)); clientDataHash = await _cryptoFunctionService.HashAsync(clientDataJSONBytes, CryptoHashAlgorithm.Sha256); } var getAssertionParams = MapToGetAssertionParams(assertCredentialParams, clientDataHash); diff --git a/src/Core/Services/Fido2MediatorService.cs b/src/Core/Services/Fido2MediatorService.cs index 35d49f173..473de47f5 100644 --- a/src/Core/Services/Fido2MediatorService.cs +++ b/src/Core/Services/Fido2MediatorService.cs @@ -18,9 +18,9 @@ namespace Bit.Core.Services _cipherService = cipherService; } - public async Task AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, byte[] clientDataHash = null) + public async Task AssertCredentialAsync(Fido2ClientAssertCredentialParams assertCredentialParams, Fido2ExtraAssertCredentialParams extraParams) { - var result = await _fido2ClientService.AssertCredentialAsync(assertCredentialParams, clientDataHash); + var result = await _fido2ClientService.AssertCredentialAsync(assertCredentialParams, extraParams); if (result?.SelectedCredential?.Cipher != null) { @@ -30,9 +30,9 @@ namespace Bit.Core.Services return result; } - public Task CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, byte[] clientDataHash = null) + public Task CreateCredentialAsync(Fido2ClientCreateCredentialParams createCredentialParams, Fido2ExtraCreateCredentialParams extraParams) { - return _fido2ClientService.CreateCredentialAsync(createCredentialParams, clientDataHash); + return _fido2ClientService.CreateCredentialAsync(createCredentialParams, extraParams); } public async Task GetAssertionAsync(Fido2AuthenticatorGetAssertionParams assertionParams, IFido2GetAssertionUserInterface userInterface) diff --git a/src/Core/Utilities/Fido2/Fido2ExtraAssertCredentialParams.cs b/src/Core/Utilities/Fido2/Fido2ExtraAssertCredentialParams.cs new file mode 100644 index 000000000..ac8c17b93 --- /dev/null +++ b/src/Core/Utilities/Fido2/Fido2ExtraAssertCredentialParams.cs @@ -0,0 +1,26 @@ +namespace Bit.Core.Utilities.Fido2 +{ + #nullable enable + + /// + /// Extra parameters for asserting a credential. + /// + public class Fido2ExtraAssertCredentialParams + { + public Fido2ExtraAssertCredentialParams(byte[]? clientDataHash = null, string? androidPackageName = null) + { + ClientDataHash = clientDataHash; + AndroidPackageName = androidPackageName; + } + + /// + /// The hash of the serialized client data. + /// + public byte[]? ClientDataHash { get; } + + /// + /// The Android package name. + /// + public string? AndroidPackageName { get; } + } +} diff --git a/src/Core/Utilities/Fido2/Fido2ExtraCreateCredentialParams.cs b/src/Core/Utilities/Fido2/Fido2ExtraCreateCredentialParams.cs new file mode 100644 index 000000000..3a66cfa42 --- /dev/null +++ b/src/Core/Utilities/Fido2/Fido2ExtraCreateCredentialParams.cs @@ -0,0 +1,26 @@ +namespace Bit.Core.Utilities.Fido2 +{ +#nullable enable + + /// + /// Extra parameters for creating a new credential. + /// + public struct Fido2ExtraCreateCredentialParams + { + public Fido2ExtraCreateCredentialParams(byte[]? clientDataHash = null, string? androidPackageName = null) + { + ClientDataHash = clientDataHash; + AndroidPackageName = androidPackageName; + } + + /// + /// The hash of the serialized client data. + /// + public byte[]? ClientDataHash { get; } + + /// + /// The Android package name. + /// + public string? AndroidPackageName { get; } + } +}