Beispiel #1
0
        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
            });
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
            }
        }