public async Task <U2fRegistration> StartU2fRegistrationAsync(User user) { await _u2fRepository.DeleteManyByUserIdAsync(user.Id); var reg = U2fLib.StartRegistration(CoreHelpers.U2fAppIdUrl(_globalSettings)); await _u2fRepository.CreateAsync(new U2f { AppId = reg.AppId, Challenge = reg.Challenge, Version = reg.Version, UserId = user.Id, CreationDate = DateTime.UtcNow }); return(new U2fRegistration { AppId = reg.AppId, Challenge = reg.Challenge, Version = reg.Version }); }
public async Task <string> GenerateAsync(string purpose, UserManager <User> manager, User user) { if (!user.Premium) { return(null); } var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); if (!HasProperMetaData(provider)) { return(null); } var keys = new List <TwoFactorProvider.U2fMetaData>(); var key1 = new TwoFactorProvider.U2fMetaData((dynamic)provider.MetaData["Key1"]); if (!key1?.Compromised ?? false) { keys.Add(key1); } if (keys.Count == 0) { return(null); } await _u2fRepository.DeleteManyByUserIdAsync(user.Id); var challenges = new List <object>(); foreach (var key in keys) { var registration = new DeviceRegistration(key.KeyHandleBytes, key.PublicKeyBytes, key.CertificateBytes, key.Counter); var auth = U2fLib.StartAuthentication(Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings), registration); // Maybe move this to a bulk create when we support more than 1 key? await _u2fRepository.CreateAsync(new U2f { AppId = auth.AppId, Challenge = auth.Challenge, KeyHandle = auth.KeyHandle, Version = auth.Version, UserId = user.Id, CreationDate = DateTime.UtcNow }); challenges.Add(new { appId = auth.AppId, challenge = auth.Challenge, keyHandle = auth.KeyHandle, version = auth.Version }); } var token = JsonConvert.SerializeObject(challenges); return(token); }
public async Task <bool> ValidateAsync(string purpose, string token, UserManager <User> manager, User user) { if (!user.Premium || string.IsNullOrWhiteSpace(token)) { return(false); } var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); if (!HasProperMetaData(provider)) { return(false); } var keys = new List <TwoFactorProvider.U2fMetaData>(); var key1 = new TwoFactorProvider.U2fMetaData((dynamic)provider.MetaData["Key1"]); if (!key1?.Compromised ?? false) { keys.Add(key1); } if (keys.Count == 0) { return(false); } var authenticateResponse = BaseModel.FromJson <AuthenticateResponse>(token); var key = keys.FirstOrDefault(f => f.KeyHandle == authenticateResponse.KeyHandle); if (key == null) { return(false); } var challenges = await _u2fRepository.GetManyByUserIdAsync(user.Id); if (challenges.Count == 0) { return(false); } // User will have a authentication request for each device they have registered so get the one that matches // the device key handle var challenge = challenges.FirstOrDefault(c => c.KeyHandle == authenticateResponse.KeyHandle); if (challenge == null) { return(false); } var success = true; var registration = new DeviceRegistration(key.KeyHandleBytes, key.PublicKeyBytes, key.CertificateBytes, key.Counter); try { var auth = new StartedAuthentication(challenge.Challenge, challenge.AppId, challenge.KeyHandle); U2fLib.FinishAuthentication(auth, authenticateResponse, registration); } catch (U2fException) { success = false; } // Update database await _u2fRepository.DeleteManyByUserIdAsync(user.Id); key.Counter = registration.Counter; key.Compromised = registration.IsCompromised; var providers = user.GetTwoFactorProviders(); providers[TwoFactorProviderType.U2f].MetaData["Key1"] = key; user.SetTwoFactorProviders(providers); await manager.UpdateAsync(user); return(success); }
public async Task <string> GenerateAsync(string purpose, UserManager <User> manager, User user) { var userService = _serviceProvider.GetRequiredService <IUserService>(); if (!(await userService.CanAccessPremium(user))) { return(null); } var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); var keys = LoadKeys(provider); if (keys.Count == 0) { return(null); } await _u2fRepository.DeleteManyByUserIdAsync(user.Id); try { var challengeBytes = U2fLib.Crypto.GenerateChallenge(); var appId = Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings); var oldChallenges = new List <object>(); var challengeKeys = new List <object>(); 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(appId, registration, challengeBytes); // TODO: Maybe move this to a bulk create? await _u2fRepository.CreateAsync(new U2f { AppId = auth.AppId, Challenge = auth.Challenge, KeyHandle = auth.KeyHandle, Version = auth.Version, UserId = user.Id, CreationDate = DateTime.UtcNow }); 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, keyHandle = auth.KeyHandle, version = auth.Version }); } var oldToken = JsonConvert.SerializeObject(oldChallenges); var token = JsonConvert.SerializeObject(new { appId = appId, challenge = challengeBytes.ByteArrayToBase64String(), keys = challengeKeys }); return($"{token}|{oldToken}"); } catch (U2fException) { return(null); } }
public async Task <bool> CompleteU2fRegistrationAsync(User user, int id, string name, string deviceResponse) { if (string.IsNullOrWhiteSpace(deviceResponse)) { return(false); } var challenges = await _u2fRepository.GetManyByUserIdAsync(user.Id); if (!challenges?.Any() ?? true) { return(false); } var registerResponse = BaseModel.FromJson <RegisterResponse>(deviceResponse); try { var challenge = challenges.OrderBy(i => i.Id).Last(i => i.KeyHandle == null); var startedReg = new StartedRegistration(challenge.Challenge, challenge.AppId); var reg = U2fLib.FinishRegistration(startedReg, registerResponse); await _u2fRepository.DeleteManyByUserIdAsync(user.Id); // Add device var providers = user.GetTwoFactorProviders(); if (providers == null) { providers = new Dictionary <TwoFactorProviderType, TwoFactorProvider>(); } var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); if (provider == null) { provider = new TwoFactorProvider(); } if (provider.MetaData == null) { provider.MetaData = new Dictionary <string, object>(); } if (provider.MetaData.Count >= 5) { // Can only register up to 5 keys return(false); } var keyId = $"Key{id}"; if (provider.MetaData.ContainsKey(keyId)) { provider.MetaData.Remove(keyId); } provider.Enabled = true; provider.MetaData.Add(keyId, new TwoFactorProvider.U2fMetaData { Name = name, KeyHandle = reg.KeyHandle == null ? null : Utils.ByteArrayToBase64String(reg.KeyHandle), PublicKey = reg.PublicKey == null ? null : Utils.ByteArrayToBase64String(reg.PublicKey), Certificate = reg.AttestationCert == null ? null : Utils.ByteArrayToBase64String(reg.AttestationCert), Compromised = false, Counter = reg.Counter }); if (providers.ContainsKey(TwoFactorProviderType.U2f)) { providers.Remove(TwoFactorProviderType.U2f); } providers.Add(TwoFactorProviderType.U2f, provider); user.SetTwoFactorProviders(providers); await UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.U2f); return(true); } catch (U2fException e) { Logger.LogError(e, "Complete U2F registration error."); return(false); } }