From 006cfffab31319924fd200d74836af09fb1cd188 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 10 Oct 2018 17:51:38 -0400 Subject: [PATCH] new "Challenge" token for U2f --- src/Core/Identity/U2fTokenProvider.cs | 27 ++++++++++++++----- .../ResourceOwnerPasswordValidator.cs | 5 +++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/Core/Identity/U2fTokenProvider.cs b/src/Core/Identity/U2fTokenProvider.cs index 73feeafc4a..2822d1c017 100644 --- a/src/Core/Identity/U2fTokenProvider.cs +++ b/src/Core/Identity/U2fTokenProvider.cs @@ -10,6 +10,7 @@ using System.Linq; using U2fLib = U2F.Core.Crypto.U2F; using U2F.Core.Models; using U2F.Core.Exceptions; +using U2F.Core.Utils; using System; using Bit.Core.Services; using Microsoft.Extensions.DependencyInjection; @@ -69,13 +70,14 @@ namespace Bit.Core.Identity try { var challengeBytes = U2fLib.Crypto.GenerateChallenge(); - var challenges = new List(); + var appId = Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings); + var oldChallenges = new List(); + var challengeKeys = new List(); foreach(var key in keys) { var registration = new DeviceRegistration(key.Item2.KeyHandleBytes, key.Item2.PublicKeyBytes, key.Item2.CertificateBytes, key.Item2.Counter); - var auth = U2fLib.StartAuthentication(Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings), registration, - challengeBytes); + var auth = U2fLib.StartAuthentication(appId, registration, challengeBytes); // TODO: Maybe move this to a bulk create? await _u2fRepository.CreateAsync(new U2f @@ -88,7 +90,14 @@ namespace Bit.Core.Identity CreationDate = DateTime.UtcNow }); - challenges.Add(new + challengeKeys.Add(new + { + keyHandle = auth.KeyHandle, + version = auth.Version + }); + + // TODO: Old challenges array is here for backwards compat. Remove in the future. + oldChallenges.Add(new { appId = auth.AppId, challenge = auth.Challenge, @@ -97,8 +106,14 @@ namespace Bit.Core.Identity }); } - var token = JsonConvert.SerializeObject(challenges); - return token; + var oldToken = JsonConvert.SerializeObject(oldChallenges); + var token = JsonConvert.SerializeObject(new + { + appId = appId, + challenge = challengeBytes.ByteArrayToBase64String(), + keys = challengeKeys + }); + return $"{token}|{oldToken}"; } catch(U2fException) { diff --git a/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs b/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs index 0e27f9999e..9abd85b2a3 100644 --- a/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs +++ b/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs @@ -327,9 +327,12 @@ namespace Bit.Core.IdentityServer } else if(type == TwoFactorProviderType.U2f) { + // TODO: Remove "Challenges" in a future update. Deprecated. + var tokens = token?.Split('|'); return new Dictionary { - ["Challenges"] = token + ["Challenge"] = tokens.Length > 0 ? tokens[0] : null, + ["Challenges"] = tokens.Length > 1 ? tokens[1] : null }; } else if(type == TwoFactorProviderType.Email)