public void Constructor_GiveValidArguments_PropertiesAreSet()
        {
            var credentialCreateOptions = new CredentialCreateOptions();
            var result = new InitiateAuthenticatorDeviceEnrollmentCommandResult(credentialCreateOptions);

            Assert.Equal(credentialCreateOptions, result.Options);
        }
        public async Task <CredentialMakeResult> MakeCredential([Required, FromBody] MakeCredentialsRequest request)
        {
            using (AuthLogic.Disable())
            {
                var optionsEntity = Database.Retrieve <WebAuthnMakeCredentialsOptionsEntity>(request.CreateOptionsId);

                var options = CredentialCreateOptions.FromJson(optionsEntity.Json);

                var result = await fido2.MakeNewCredentialAsync(request.AttestationRawResponse, options, async (args) =>
                {
                    return(!(await Database.Query <WebAuthnCredentialEntity>().AnyAsync(c => c.CredentialId == args.CredentialId)));
                });

                if (result.Status != "ok")
                {
                    throw new InvalidOperationException(options.ErrorMessage);
                }

                new WebAuthnCredentialEntity
                {
                    CredentialId = result.Result.CredentialId,
                    PublicKey    = result.Result.PublicKey,
                    User         = Lite.ParsePrimaryKey <UserEntity>(Encoding.UTF8.GetString(result.Result.User.Id)),
                    Counter      = (int)result.Result.Counter,
                    CredType     = result.Result.CredType,
                    Aaguid       = result.Result.Aaguid,
                }.Save();

                return(result);
            }
        }
Esempio n. 3
0
 public EnrollAuthenticatorDeviceCommand(string name, AuthenticatorAttestationRawResponse authenticatorAttestationRawResponse,
                                         CredentialCreateOptions credentialCreateOptions)
 {
     this.AuthenticatorAttestationRawResponse = authenticatorAttestationRawResponse;
     this.CredentialCreateOptions             = credentialCreateOptions;
     this.Name = name;
 }
Esempio n. 4
0
        public async Task <JsonResult> MakeCredentialResultTest([FromBody] AuthenticatorAttestationRawResponse attestationResponse)
        {
            // 1. get the options we sent the client
            var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
            var options     = CredentialCreateOptions.FromJson(jsonOptions);

            // 2. Create callback so that lib can verify credential id is unique to this user
            IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
            {
                var users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId);

                if (users.Count > 0)
                {
                    return(false);
                }

                return(true);
            };

            // 2. Verify and make the credentials
            var success = await _lib.MakeNewCredentialAsync(attestationResponse, options, callback);

            // 3. Store the credentials in db
            DemoStorage.AddCredentialToUser(options.User, new StoredCredential
            {
                Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                PublicKey        = success.Result.PublicKey,
                UserHandle       = success.Result.User.Id,
                SignatureCounter = success.Result.Counter
            });

            // 4. return "ok" to the client
            return(Json(success));
        }
Esempio n. 5
0
        public void Constructor_GiveValidArguments_PropertiesAreSet()
        {
            var authenticatorAttestationRawResponse = new AuthenticatorAttestationRawResponse();
            var credentialCreateOptions             = new CredentialCreateOptions();
            var command = new EnrollAuthenticatorDeviceCommand("name", authenticatorAttestationRawResponse, credentialCreateOptions);

            Assert.Equal("name", command.Name);
            Assert.Equal(authenticatorAttestationRawResponse, command.AuthenticatorAttestationRawResponse);
            Assert.Equal(credentialCreateOptions, command.CredentialCreateOptions);
        }
        public async Task <JsonResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse attestationResponse, CancellationToken cancellationToken)
        {
            try
            {
                // 1. get the options we sent the client
                var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
                var options     = CredentialCreateOptions.FromJson(jsonOptions);

                // 2. Create callback so that lib can verify credential id is unique to this user
                IsCredentialIdUniqueToUserAsyncDelegate callback = static async(args, cancellationToken) =>
        public async Task <CacheItem> ExecuteAsync(string fido2Payload, CacheItem relatedItem)
        {
            var request = OwnIdSerializer.Deserialize <Fido2RegisterRequest>(fido2Payload);

            if (string.IsNullOrWhiteSpace(request.AttestationObject))
            {
                throw new CommandValidationException("Incorrect Fido2 register request: AttestationObject is missing");
            }

            if (string.IsNullOrWhiteSpace(request.ClientDataJson))
            {
                throw new CommandValidationException("Incorrect Fido2 register request: ClientDataJson is missing");
            }

            var fido2Response = new AuthenticatorAttestationRawResponse
            {
                Id       = _encodingService.Base64UrlDecode(NewUserId),
                RawId    = _encodingService.Base64UrlDecode(NewUserId),
                Type     = PublicKeyCredentialType.PublicKey,
                Response = new AuthenticatorAttestationRawResponse.ResponseData
                {
                    AttestationObject = _encodingService.Base64UrlDecode(request.AttestationObject),
                    ClientDataJson    = _encodingService.Base64UrlDecode(request.ClientDataJson)
                }
            };

            var options = new CredentialCreateOptions
            {
                Challenge = _encodingService.ASCIIDecode(relatedItem.Context),
                Rp        = new PublicKeyCredentialRpEntity(
                    _configuration.Fido2.RelyingPartyId,
                    _configuration.Fido2.RelyingPartyName,
                    null),
                User = new Fido2User
                {
                    DisplayName = _configuration.Fido2.UserDisplayName,
                    Name        = _configuration.Fido2.UserName,
                    Id          = _encodingService.Base64UrlDecode(NewUserId)
                }
            };

            var result = await _fido2.MakeNewCredentialAsync(fido2Response, options, args => Task.FromResult(true));

            if (result == null)
            {
                throw new InternalLogicException("Cannot verify fido2 register request");
            }

            var publicKey = _encodingService.Base64UrlEncode(result.Result.PublicKey);

            return(await ProcessFido2RegisterResponseAsync(relatedItem, publicKey, result.Result.Counter,
                                                           _encodingService.Base64UrlEncode(result.Result.CredentialId)));
        }
Esempio n. 8
0
        /// <summary>
        /// 注册:验证用户凭证
        /// <para>当客户端返回响应时,我们验证并注册凭据。</para>
        /// </summary>
        /// <param name="attestationResponse"></param>
        public async Task <CredentialMakeResult> RegisterCredentials(User user, string fido2Name, AuthenticatorAttestationRawResponse attestationResponse)
        {
            // 1. get the options we sent the client
            var jsonOptions = distributedCache.GetString(user.UserId.ToString() + "attestationOptions");

            if (string.IsNullOrEmpty(jsonOptions))
            {
                return(null);
            }
            var options = CredentialCreateOptions.FromJson(jsonOptions);

            // 2. Create callback so that lib can verify credential id is unique to this user
            IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
            {
                //var users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId);
                //if (users.Count > 0)
                //    return false;
                var argUserId = args.CredentialId;
                if (this.dataContext.FIDO2Repository.Where(b => b.CredentialId.Equals(argUserId)).Any())
                {
                    return(false);
                }
                return(true);
            };
            // 2. Verify and make the credentials
            var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback);

            // 3. Store the credentials in db
            //var user = dataContext.User.Where(b => b.UserId == userId).FirstOrDefault();
            if (user == null)
            {
                return(null);
            }
            var fido2 = new FIDO2Item()
            {
                Id               = IdGenerator.NextId(),
                UserId           = user.UserId,
                FIDO2Name        = fido2Name,
                CredentialId     = success.Result.CredentialId,
                PublicKey        = success.Result.PublicKey,
                UserHandle       = success.Result.User.Id,
                SignatureCounter = success.Result.Counter,
                CredType         = success.Result.CredType,
                RegDate          = DateTime.Now,
                AaGuid           = success.Result.Aaguid
            };

            dataContext.FIDO2Repository.Add(fido2);

            dataContext.SaveChanges();

            return(success);
        }
        public async Task <ActionResult <CredentialMakeResult> > MakeCredential(AuthenticatorAttestationRawResponse attestationResponse)
        {
            try
            {
                // 1. get the options we sent the client
                var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
                var options     = CredentialCreateOptions.FromJson(jsonOptions);

                // 2. Create callback so that lib can verify credential id is unique to this user
                IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
                {
                    var credentialIdString = Base64Url.Encode(args.CredentialId);
                    var cred = await context.StoredCredentials.Where(x => x.DescriptorJson.Contains(credentialIdString)).FirstOrDefaultAsync();

                    if (cred == null)
                    {
                        return(true);
                    }
                    var users = await context.Members.Where(x => x.UserId == cred.UserId).Select(u => new Fido2User
                    {
                        DisplayName = u.DisplayName,
                        Name        = u.UserName,
                        Id          = u.UserId
                    }).ToListAsync();

                    return(users.Count == 0);
                };

                // 2. Verify and make the credentials
                var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback);

                context.StoredCredentials.Add(new StoredCredential
                {
                    Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                    UserId           = options.User.Id,
                    PublicKey        = success.Result.PublicKey,
                    UserHandle       = success.Result.User.Id,
                    SignatureCounter = success.Result.Counter,
                    CredType         = success.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = success.Result.Aaguid
                });
                await context.SaveChangesAsync();

                return(Ok(success));
            }
            catch (Exception e)
            {
                return(BadRequest(new CredentialMakeResult {
                    Status = "error", ErrorMessage = FormatException(e)
                }));
            }
        }
Esempio n. 10
0
        public async Task <IActionResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse attestationResponse)
        {
            var o = new
            {
                challenge = string.Empty,
                origin    = string.Empty,
                type      = string.Empty
            };

            var username = string.Empty;

            try
            {
                o = JsonConvert.DeserializeAnonymousType((Encoding.UTF8.GetString(attestationResponse.Response.ClientDataJson)), o);
                var jsonOptions = _memoryCache.Get <string>(o.challenge);
                var options     = CredentialCreateOptions.FromJson(jsonOptions);
                username = options.User.Name;

                async Task <bool> Callback(IsCredentialIdUniqueToUserParams args)
                {
                    var users = await _dataStore.GetUsersByCredentialIdAsync(args.CredentialId);

                    return(users.Count <= 0);
                }

                var success = await _lib.MakeNewCredentialAsync(attestationResponse, options, Callback);

                _dataStore.AddCredentialToUser(options.User, new StoredCredential
                {
                    Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                    PublicKey        = success.Result.PublicKey,
                    UserHandle       = success.Result.User.Id,
                    SignatureCounter = success.Result.Counter,
                    CredType         = success.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = success.Result.Aaguid
                });

                var ev = new Event(username, "Successfully logged the person in", nameof(RegistrationController), nameof(MakeCredential));
                await _elasticClient.IndexAsync(ev, i => i.Index(GetIndexName(nameof(Ok))));

                return(Ok(success));
            }
            catch (Exception e)
            {
                var errorEvent = new ErrorEvent(e, username, nameof(RegistrationController), nameof(MakeCredential));
                await _elasticClient.IndexAsync(errorEvent, i => i.Index(GetIndexName(nameof(Exception))));

                return(Ok(new Fido2.CredentialMakeResult {
                    Status = "error", ErrorMessage = FormatException(e) + $"ClientDataJson = {Encoding.UTF8.GetString(attestationResponse.Response.ClientDataJson)}"
                }));
            }
        }
Esempio n. 11
0
        public async Task <ActionResult> MakeCredential([ModelBinder(typeof(NewtonsoftJsonAdapter.Binder))] MakeCredentialRequest request)
        {
            var subjectId = User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;

            try
            {
                // 1. get the options we sent the client
                var jsonOptions = TestUsers.FidoAttestationOptions[request.SessionId];
                var options     = CredentialCreateOptions.FromJson(jsonOptions);

                // 2. Verify and make the credentials
                var success = await _lib.MakeNewCredentialAsync(
                    attestationResponse : request.AttestationResponse,
                    origChallenge : options,
                    isCredentialIdUniqueToUser : async(IsCredentialIdUniqueToUserParams args) =>
                {
                    var users = TestUsers.FidoCredentials.Where(c => c.Descriptor.Id.SequenceEqual(args.CredentialId)).ToList();
                    if (users.Count > 0)
                    {
                        return(false);
                    }

                    return(true);
                });

                // 3. Store the credentials in db
                TestUsers.FidoCredentials.Add(new TestUsers.StoredFidoCredential
                {
                    UserId           = options.User.Id,
                    SubjectId        = subjectId,
                    Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                    PublicKey        = success.Result.PublicKey,
                    UserHandle       = success.Result.User.Id,
                    SignatureCounter = success.Result.Counter,
                    CredType         = success.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = success.Result.Aaguid
                });

                // 4. return "ok" to the client
                return(Ok(success));
            }
            catch (Exception e)
            {
                return(BadRequest(new CredentialMakeResult {
                    Status = "error", ErrorMessage = FormatException(e)
                }));
            }
        }
Esempio n. 12
0
        public async Task <IActionResult> CompleteAuthDeviceRegistration(
            [FromBody] CompleteAuthDeviceRegistrationRequest model)
        {
            var jsonOptions = this.TempData["CredentialData"] as string;
            var options     = CredentialCreateOptions.FromJson(jsonOptions);

            var result = await this._mediator.Send(new EnrollAuthenticatorDeviceCommand(
                                                       model.Name,
                                                       model.AttestationResponse,
                                                       options));

            return(this.Json(result.IsFailure
                ? new CompleteAuthDeviceRegistrationResponse()
                : new CompleteAuthDeviceRegistrationResponse(result.Value.CredentialMakeResult, result.Value.DeviceId, model.Name)));
        }
Esempio n. 13
0
        public async Task <ActionResult> MakeCredential(
            [FromBody] AuthenticatorAttestationRawResponse attestationResponse)
        {
            try
            {
                // 1. get the options we sent the client
                var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
                var options     = CredentialCreateOptions.FromJson(jsonOptions);

                // 2. Create callback so that lib can verify credential id is unique to this user
                IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
                {
                    var users = await fidoStore.GetUsersByCredentialIdAsync(args.CredentialId);

                    if (users.Count > 0)
                    {
                        return(false);
                    }

                    return(true);
                };

                // 2. Verify and make the credentials
                var success = await fido2.MakeNewCredentialAsync(attestationResponse, options, callback);

                // 3. Store the credentials in db
                fidoStore.AddCredentialToUser(options.User, new StoredCredential
                {
                    Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                    PublicKey        = success.Result.PublicKey,
                    UserHandle       = success.Result.User.Id,
                    SignatureCounter = success.Result.Counter,
                    CredType         = success.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = success.Result.Aaguid
                });

                // 4. return "ok" to the client
                return(Ok(success));
            }
            catch (Exception e)
            {
                return(BadRequest(new Fido2.CredentialMakeResult {
                    Status = "error", ErrorMessage = FormatException(e)
                }));
            }
        }
Esempio n. 14
0
        public async Task <JsonResult> SaveCredentials([FromBody] AuthenticatorAttestationRawResponse attestationResponse)
        {
            try
            {
                var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
                var options     = CredentialCreateOptions.FromJson(jsonOptions);

                var fidoCredentials = await fido2.MakeNewCredentialAsync(attestationResponse, options, IsCredentialUnique);

                var storedCredential = new StoredCredential
                {
                    Descriptor       = new PublicKeyCredentialDescriptor(fidoCredentials.Result.CredentialId),
                    PublicKey        = fidoCredentials.Result.PublicKey,
                    UserHandle       = fidoCredentials.Result.User.Id,
                    SignatureCounter = fidoCredentials.Result.Counter,
                    CredType         = fidoCredentials.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = fidoCredentials.Result.Aaguid
                };

                var names  = options.User.DisplayName.Split(' ');
                var result = await oktaClient.Users.CreateUserAsync(new CreateUserWithoutCredentialsOptions
                {
                    Profile = new UserProfile
                    {
                        Login                     = options.User.Name,
                        Email                     = options.User.Name,
                        DisplayName               = options.User.DisplayName,
                        FirstName                 = names[0],
                        LastName                  = names[1],
                        ["CredentialId"]          = Convert.ToBase64String(fidoCredentials.Result.CredentialId),
                        ["PasswordlessPublicKey"] = JsonConvert.SerializeObject(storedCredential)
                    }
                });

                return(Json(fidoCredentials));
            }
            catch (Exception e)
            {
                return(Json(new Fido2.CredentialMakeResult {
                    Status = "error", ErrorMessage = e.Message
                }));
            }
        }
Esempio n. 15
0
        public async Task <IActionResult> CompleteAuthDeviceRegistration(
            [FromBody] CompleteAuthDeviceRegistrationRequest model)
        {
            var jsonOptions = this.TempData["CredentialData"] as string;
            var options     = CredentialCreateOptions.FromJson(jsonOptions);

            var result = await this._mediator.Send(new EnrollDeviceCommand(
                                                       model.Name,
                                                       model.AttestationResponse,
                                                       options));

            if (result.IsFailure)
            {
                return(this.Json(new Fido2.CredentialMakeResult {
                    Status = "error"
                }));
            }


            return(this.Json(result.Value.CredentialMakeResult));
        }
Esempio n. 16
0
        public async Task <bool> CompleteWebAuthRegistrationAsync(User user, int id, string name, AuthenticatorAttestationRawResponse attestationResponse)
        {
            var keyId = $"Key{id}";

            var provider = user.GetTwoFactorProvider(TwoFactorProviderType.WebAuthn);

            if (!provider?.MetaData?.ContainsKey("pending") ?? true)
            {
                return(false);
            }

            var options = CredentialCreateOptions.FromJson((string)provider.MetaData["pending"]);

            // Callback to ensure credential id is unique. Always return true since we don't care if another
            // account uses the same 2fa key.
            IsCredentialIdUniqueToUserAsyncDelegate callback = args => Task.FromResult(true);

            var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback);

            provider.MetaData.Remove("pending");
            provider.MetaData[keyId] = new TwoFactorProvider.WebAuthnData
            {
                Name             = name,
                Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                PublicKey        = success.Result.PublicKey,
                UserHandle       = success.Result.User.Id,
                SignatureCounter = success.Result.Counter,
                CredType         = success.Result.CredType,
                RegDate          = DateTime.Now,
                AaGuid           = success.Result.Aaguid
            };

            var providers = user.GetTwoFactorProviders();

            providers[TwoFactorProviderType.WebAuthn] = provider;
            user.SetTwoFactorProviders(providers);
            await UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.WebAuthn);

            return(true);
        }
        public async Task <JsonResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse attestationResponse, [FromQuery] CredentialCreateOptions options)
        {
            var user = await GetCurrentLocalUserAsync();

            try
            {
                // 2. Create callback so that lib can verify credential id is unique to this user
                IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
                {
                    var users = await _auth.GetUserIdsByCredentialIdAsync(args.CredentialId);

                    if (users.Count > 0)
                    {
                        return(false);
                    }

                    return(true);
                };

                // 2. Verify and make the credentials
                var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback);

                // 3. Store the credentials in db
                await _auth.AddCredential(user, new StoredCredential
                {
                    Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                    PublicKey        = success.Result.PublicKey,
                    UserId           = BitConverter.GetBytes(user.Id),
                    UserHandle       = success.Result.User.Id,
                    SignatureCounter = success.Result.Counter,
                    CredType         = success.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = success.Result.Aaguid
                });

                // 4. return "ok" to the client
                return(Json(success));
            }
            catch (Exception e)
            {
                return(Json(new { Status = "error", ErrorMessage = e.Message }));
            }
        }
        public void TestAuthenticatorAttestationResponseNotUserPresent()
        {
            var challenge = RandomGenerator.Default.GenerateBytes(128);
            var rp        = "https://www.passwordless.dev";
            var authData  = new AuthenticatorData(
                SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(rp)),
                AuthenticatorFlags.UV,
                0,
                null,
                null
                ).ToByteArray();
            var clientDataJson = Encoding.UTF8.GetBytes(
                JsonConvert.SerializeObject
                (
                    new
            {
                Type      = "webauthn.create",
                Challenge = challenge,
                Origin    = rp,
            }
                )
                );
            var rawResponse = new AuthenticatorAttestationRawResponse
            {
                Type     = PublicKeyCredentialType.PublicKey,
                Id       = new byte[] { 0xf1, 0xd0 },
                RawId    = new byte[] { 0xf1, 0xd0 },
                Response = new AuthenticatorAttestationRawResponse.ResponseData()
                {
                    AttestationObject = CBORObject.NewMap().Add("fmt", "testing").Add("attStmt", CBORObject.NewMap()).Add("authData", authData).EncodeToBytes(),
                    ClientDataJson    = clientDataJson
                },
            };

            var origChallenge = new CredentialCreateOptions
            {
                Attestation            = AttestationConveyancePreference.Direct,
                AuthenticatorSelection = new AuthenticatorSelection
                {
                    AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform,
                    RequireResidentKey      = true,
                    UserVerification        = UserVerificationRequirement.Required,
                },
                Challenge        = challenge,
                ErrorMessage     = "",
                PubKeyCredParams = new List <PubKeyCredParam>()
                {
                    new PubKeyCredParam
                    {
                        Alg  = COSE.Algorithm.ES256,
                        Type = PublicKeyCredentialType.PublicKey,
                    }
                },
                Rp     = new PublicKeyCredentialRpEntity(rp, rp, ""),
                Status = "ok",
                User   = new Fido2User
                {
                    Name        = "testuser",
                    Id          = Encoding.UTF8.GetBytes("testuser"),
                    DisplayName = "Test User",
                },
                Timeout = 60000,
            };

            IsCredentialIdUniqueToUserAsyncDelegate callback = (args) =>
            {
                return(Task.FromResult(true));
            };

            var lib = new Fido2(new Fido2Configuration()
            {
                ServerDomain = rp,
                ServerName   = rp,
                Origin       = rp,
            });

            var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => lib.MakeNewCredentialAsync(rawResponse, origChallenge, callback));

            Assert.Equal("User Present flag not set in authenticator data", ex.Result.Message);
        }
        public async Task TestAuthenticatorOrigins(string origin, string expectedOrigin)
        {
            var challenge = RandomGenerator.Default.GenerateBytes(128);
            var rp        = origin;
            var acd       = new AttestedCredentialData(("00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-40-FE-6A-32-63-BE-37-D1-01-B1-2E-57-CA-96-6C-00-22-93-E4-19-C8-CD-01-06-23-0B-C6-92-E8-CC-77-12-21-F1-DB-11-5D-41-0F-82-6B-DB-98-AC-64-2E-B1-AE-B5-A8-03-D1-DB-C1-47-EF-37-1C-FD-B1-CE-B0-48-CB-2C-A5-01-02-03-26-20-01-21-58-20-A6-D1-09-38-5A-C7-8E-5B-F0-3D-1C-2E-08-74-BE-6D-BB-A4-0B-4F-2A-5F-2F-11-82-45-65-65-53-4F-67-28-22-58-20-43-E1-08-2A-F3-13-5B-40-60-93-79-AC-47-42-58-AA-B3-97-B8-86-1D-E4-41-B4-4E-83-08-5D-1C-6B-E0-D0").Split('-').Select(c => Convert.ToByte(c, 16)).ToArray());
            var authData  = new AuthenticatorData(
                SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(origin)),
                AuthenticatorFlags.UP | AuthenticatorFlags.AT,
                0,
                acd,
                null
                ).ToByteArray();
            var clientDataJson = Encoding.UTF8.GetBytes(
                JsonConvert.SerializeObject
                (
                    new
            {
                Type      = "webauthn.create",
                Challenge = challenge,
                Origin    = rp,
            }
                )
                );
            var rawResponse = new AuthenticatorAttestationRawResponse
            {
                Type     = PublicKeyCredentialType.PublicKey,
                Id       = new byte[] { 0xf1, 0xd0 },
                RawId    = new byte[] { 0xf1, 0xd0 },
                Response = new AuthenticatorAttestationRawResponse.ResponseData()
                {
                    AttestationObject = CBORObject.NewMap().Add("fmt", "none").Add("attStmt", CBORObject.NewMap()).Add("authData", authData).EncodeToBytes(),
                    ClientDataJson    = clientDataJson
                },
            };

            var origChallenge = new CredentialCreateOptions
            {
                Attestation            = AttestationConveyancePreference.Direct,
                AuthenticatorSelection = new AuthenticatorSelection
                {
                    AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform,
                    RequireResidentKey      = true,
                    UserVerification        = UserVerificationRequirement.Required,
                },
                Challenge        = challenge,
                ErrorMessage     = "",
                PubKeyCredParams = new List <PubKeyCredParam>()
                {
                    new PubKeyCredParam
                    {
                        Alg  = COSE.Algorithm.ES256,
                        Type = PublicKeyCredentialType.PublicKey,
                    }
                },
                Rp     = new PublicKeyCredentialRpEntity(rp, rp, ""),
                Status = "ok",
                User   = new Fido2User
                {
                    Name        = "testuser",
                    Id          = Encoding.UTF8.GetBytes("testuser"),
                    DisplayName = "Test User",
                },
                Timeout = 60000,
            };

            IsCredentialIdUniqueToUserAsyncDelegate callback = (args) =>
            {
                return(Task.FromResult(true));
            };

            var lib = new Fido2(new Fido2Configuration()
            {
                ServerDomain = rp,
                ServerName   = rp,
                Origin       = expectedOrigin,
            });

            var result = await lib.MakeNewCredentialAsync(rawResponse, origChallenge, callback);
        }
            public async Task <Fido2.CredentialMakeResult> MakeAttestationResponse()
            {
                _attestationObject.Set("authData", _authData);

                var attestationResponse = new AuthenticatorAttestationRawResponse
                {
                    Type     = PublicKeyCredentialType.PublicKey,
                    Id       = new byte[] { 0xf1, 0xd0 },
                    RawId    = new byte[] { 0xf1, 0xd0 },
                    Response = new AuthenticatorAttestationRawResponse.ResponseData()
                    {
                        AttestationObject = _attestationObject.EncodeToBytes(),
                        ClientDataJson    = _clientDataJson,
                    },
                    Extensions = new AuthenticationExtensionsClientOutputs()
                    {
                        AppID = true,
                        AuthenticatorSelection = true,
                        BiometricAuthenticatorPerformanceBounds = true,
                        GenericTransactionAuthorization         = new byte[] { 0xf1, 0xd0 },
                        SimpleTransactionAuthorization          = "test",
                        Extensions             = new string[] { "foo", "bar" },
                        Example                = "test",
                        Location               = new GeoCoordinatePortable.GeoCoordinate(42.523714, -71.040860),
                        UserVerificationIndex  = new byte[] { 0xf1, 0xd0 },
                        UserVerificationMethod = new ulong[][]
                        {
                            new ulong[]
                            {
                                4 // USER_VERIFY_PASSCODE_INTERNAL
                            },
                        },
                    }
                };

                var origChallenge = new CredentialCreateOptions
                {
                    Attestation            = AttestationConveyancePreference.Direct,
                    AuthenticatorSelection = new AuthenticatorSelection
                    {
                        AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform,
                        RequireResidentKey      = true,
                        UserVerification        = UserVerificationRequirement.Required,
                    },
                    Challenge        = _challenge,
                    ErrorMessage     = "",
                    PubKeyCredParams = new List <PubKeyCredParam>()
                    {
                        new PubKeyCredParam
                        {
                            Alg  = COSE.Algorithm.ES256,
                            Type = PublicKeyCredentialType.PublicKey,
                        }
                    },
                    Rp     = new PublicKeyCredentialRpEntity(rp, rp, ""),
                    Status = "ok",
                    User   = new Fido2User
                    {
                        Name        = "testuser",
                        Id          = Encoding.UTF8.GetBytes("testuser"),
                        DisplayName = "Test User",
                    },
                    Timeout = 60000,
                };

                IsCredentialIdUniqueToUserAsyncDelegate callback = (args) =>
                {
                    return(Task.FromResult(true));
                };

                var lib = new Fido2(new Fido2Configuration()
                {
                    ServerDomain = rp,
                    ServerName   = rp,
                    Origin       = rp,
                });

                var credentialMakeResult = await lib.MakeNewCredentialAsync(attestationResponse, origChallenge, callback);

                return(credentialMakeResult);
            }
Esempio n. 21
0
        public async Task <IActionResult> RegisterCallback([FromBody] AuthenticatorAttestationRawResponse model)
        {
            var sub = HttpContext.User.Claims.FirstOrDefault(x => x.Type == "sub")?.Value;

            if (string.IsNullOrEmpty(sub))
            {
                return(RedirectToAction("Index", "Home"));
            }
            var user = await _users.FindByIdAsync(sub);

            if (user == null)
            {
                return(RedirectToAction("Index", "Home"));
            }

            try
            {
                // 1. get the options we sent the client
                var jsonOptions       = HttpContext.Session.GetString("fido2.attestationOptions");
                var options           = CredentialCreateOptions.FromJson(jsonOptions);
                var authenticatorName = HttpContext.Session.GetString("fido2.attestationOptions.authenticatorType");
                // 2. Create callback so that lib can verify credential id is unique to this user
                IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
                {
                    var users = _authContext.FidoLogins.Where(l => l.PublicKeyIdBytes.SequenceEqual(args.CredentialId));
                    if (users.Count() > 0)
                    {
                        return(false);
                    }

                    return(true);
                };

                // 2. Verify and make the credentials
                var success = await _lib.MakeNewCredentialAsync(model, options, callback);

                var parsedResponse = AuthenticatorAttestationResponse.Parse(model);;
                var authData       = new AuthenticatorData(parsedResponse.AttestationObject.AuthData);
                var dbUser         = _authContext.Users.First(x => x.Id == user.Id);
                dbUser.TwoFactorEnabled = true;
                var login = new FidoLogin()
                {
                    PublicKeyIdBytes  = success.Result.CredentialId,
                    PublicKeyId       = Fido2NetLib.Base64Url.Encode(success.Result.CredentialId),
                    AaGuid            = success.Result.Aaguid.ToString(),
                    PublicKey         = success.Result.PublicKey,
                    SignatureCounter  = success.Result.Counter,
                    CredType          = success.Result.CredType,
                    RegistrationDate  = DateTime.Now,
                    User              = dbUser,
                    UserHandle        = success.Result.User.Id,
                    AuthenticatorName = authenticatorName
                };
                _authContext.FidoLogins.Add(login);
                _authContext.SaveChanges();


                // 4. return "ok" to the client
                return(Json(new { success = true }));
            }
            catch (Exception e)
            {
                return(Json(new { error = true }));
            }
        }
Esempio n. 22
0
 public InitiateAuthenticatorDeviceEnrollmentCommandResult(CredentialCreateOptions options)
 {
     this.Options = options;
 }
        public async Task <JsonResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse attestationResponse)
        {
            try
            {
                // 1. get the options we sent the client
                var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
                var options     = CredentialCreateOptions.FromJson(jsonOptions);

                // 2. Create callback so that lib can verify credential id is unique to this user
                IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
                {
                    var users = await _fido2Storage.GetUsersByCredentialIdAsync(args.CredentialId);

                    if (users.Count > 0)
                    {
                        return(false);
                    }

                    return(true);
                };

                // 2. Verify and make the credentials
                var success = await _lib.MakeNewCredentialAsync(attestationResponse, options, callback);

                // 3. Store the credentials in db
                await _fido2Storage.AddCredentialToUser(options.User, new FidoStoredCredential
                {
                    Username         = options.User.Name,
                    Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                    PublicKey        = success.Result.PublicKey,
                    UserHandle       = success.Result.User.Id,
                    SignatureCounter = success.Result.Counter,
                    CredType         = success.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = success.Result.Aaguid
                });

                // 4. return "ok" to the client

                var user = await _userManager.GetUserAsync(User);

                if (user == null)
                {
                    return(Json(new CredentialMakeResult {
                        Status = "error", ErrorMessage = _sharedLocalizer["FIDO2_USER_NOTFOUND", _userManager.GetUserId(User)]
                    }));
                }

                await _userManager.SetTwoFactorEnabledAsync(user, true);

                var userId = await _userManager.GetUserIdAsync(user);

                return(Json(success));
            }
            catch (Exception e)
            {
                return(Json(new CredentialMakeResult {
                    Status = "error", ErrorMessage = FormatException(e)
                }));
            }
        }
        public async Task <JsonResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse authenticatorAttestationRawResponse)
        {
            try
            {
                var user = await _userManager.GetUserAsync(User);

                if (user == null)
                {
                    throw new Exception("Unable to retrieve user.");
                }

                var jsonOptions = await _distributedCache.GetStringAsync(UniqueId);

                if (string.IsNullOrEmpty(jsonOptions))
                {
                    throw new Exception("Cant get Credential options from cache.");
                }
                var options = CredentialCreateOptions.FromJson(jsonOptions);

                IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUserAsyncDelegate = async(IsCredentialIdUniqueToUserParams isCredentialIdUniqueToUserParams) =>
                {
                    var fido2Users = await _fido2Service.GetFido2UsersByCredentialIdAsync(isCredentialIdUniqueToUserParams.CredentialId);

                    if (fido2Users.Count > 0)
                    {
                        return(false);
                    }
                    return(true);
                };
                var result = await _fido2.MakeNewCredentialAsync(authenticatorAttestationRawResponse, options, isCredentialIdUniqueToUserAsyncDelegate);

                if (result.Status != "ok")
                {
                    throw new Exception("Unable to create credential.");
                }


                var newFido2StoredCredential = new Fido2StoredCredential {
                };
                newFido2StoredCredential.UserName         = options.User.Name;
                newFido2StoredCredential.UserId           = options.User.Id;
                newFido2StoredCredential.PublicKey        = result.Result.PublicKey;
                newFido2StoredCredential.UserHandle       = result.Result.User.Id;
                newFido2StoredCredential.SignatureCounter = result.Result.Counter;
                newFido2StoredCredential.CredType         = result.Result.CredType;
                newFido2StoredCredential.RegDate          = DateTime.Now;
                newFido2StoredCredential.AaGuid           = Guid.NewGuid();
                newFido2StoredCredential.Descriptor       = new PublicKeyCredentialDescriptor(result.Result.CredentialId);

                _fido2Service.AddFido2StoredCredential(newFido2StoredCredential);

                return(Json(result));
            }
            catch (Exception exception)
            {
                return(Json(new CredentialCreateOptions()
                {
                    Status = "error", ErrorMessage = CommonFunctions.FormatException(exception)
                }));
            }
        }
Esempio n. 25
0
        public async Task TestApplePublicKeyMismatch()
        {
            var cpkBytes = new byte[] { 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x79, 0xfe, 0x59, 0x08, 0xbb, 0x51, 0x29, 0xc8, 0x09, 0x38, 0xb7, 0x54, 0xc0, 0x4d, 0x2b, 0x34, 0x0e, 0xfa, 0x66, 0x15, 0xb9, 0x87, 0x69, 0x8b, 0xf5, 0x9d, 0xa4, 0xe5, 0x3e, 0xa3, 0xe6, 0xfe, 0x22, 0x58, 0x20, 0xfb, 0x03, 0xda, 0xa1, 0x27, 0x0d, 0x58, 0x04, 0xe8, 0xab, 0x61, 0xc1, 0x5a, 0xac, 0xa2, 0x43, 0x5c, 0x7d, 0xbf, 0x36, 0x9d, 0x71, 0xca, 0x15, 0xc5, 0x23, 0xb0, 0x00, 0x4a, 0x1b, 0x75, 0xb7 };

            _credentialPublicKey = new CredentialPublicKey(cpkBytes);

            var authData = new AuthenticatorData(_rpIdHash, _flags, _signCount, _acd, _exts).ToByteArray();

            _attestationObject.Set("authData", new CborByteString(authData));
            var clientData = new
            {
                type      = "webauthn.create",
                challenge = _challenge,
                origin    = "https://www.passwordless.dev",
            };
            var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(clientData);

            var invalidX5cStrings = StackAllocSha256(authData, clientDataJson);

            var trustPath = invalidX5cStrings
                            .Select(x => new X509Certificate2(Convert.FromBase64String(x)))
                            .ToArray();

            var X5c = new CborArray {
                { trustPath[0].RawData },
                { trustPath[1].RawData }
            };

            ((CborMap)_attestationObject["attStmt"]).Set("x5c", X5c);

            var attestationResponse = new AuthenticatorAttestationRawResponse
            {
                Type     = PublicKeyCredentialType.PublicKey,
                Id       = new byte[] { 0xf1, 0xd0 },
                RawId    = new byte[] { 0xf1, 0xd0 },
                Response = new AuthenticatorAttestationRawResponse.ResponseData()
                {
                    AttestationObject = _attestationObject.Encode(),
                    ClientDataJson    = clientDataJson,
                }
            };

            var origChallenge = new CredentialCreateOptions
            {
                Attestation            = AttestationConveyancePreference.Direct,
                AuthenticatorSelection = new AuthenticatorSelection
                {
                    AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform,
                    RequireResidentKey      = true,
                    UserVerification        = UserVerificationRequirement.Discouraged,
                },
                Challenge        = _challenge,
                ErrorMessage     = "",
                PubKeyCredParams = new List <PubKeyCredParam>()
                {
                    new PubKeyCredParam(COSE.Algorithm.ES256)
                },
                Rp     = new PublicKeyCredentialRpEntity("https://www.passwordless.dev", "6cc3c9e7967a.ngrok.io", ""),
                Status = "ok",
                User   = new Fido2User
                {
                    Name        = "testuser",
                    Id          = Encoding.UTF8.GetBytes("testuser"),
                    DisplayName = "Test User",
                },
                Timeout = 60000,
            };

            IsCredentialIdUniqueToUserAsyncDelegate callback = (args, cancellationToken) =>
            {
                return(Task.FromResult(true));
            };

            IFido2 lib = new Fido2(new Fido2Configuration()
            {
                ServerDomain = "6cc3c9e7967a.ngrok.io",
                ServerName   = "6cc3c9e7967a.ngrok.io",
                Origins      = new HashSet <string> {
                    "https://www.passwordless.dev"
                },
            });

            var credentialMakeResult = await lib.MakeNewCredentialAsync(attestationResponse, origChallenge, callback);
        }
        public void TestAuthenticatorAttestationResponseInvalidRawType()
        {
            var challenge      = RandomGenerator.Default.GenerateBytes(128);
            var rp             = "fido2.azurewebsites.net";
            var clientDataJson = Encoding.UTF8.GetBytes(
                JsonConvert.SerializeObject
                (
                    new
            {
                Type      = "webauthn.create",
                Challenge = challenge,
                Origin    = rp,
            }
                )
                );
            var rawResponse = new AuthenticatorAttestationRawResponse
            {
                Type     = null,
                Id       = new byte[] { 0xf1, 0xd0 },
                RawId    = new byte[] { 0xf1, 0xd0 },
                Response = new AuthenticatorAttestationRawResponse.ResponseData()
                {
                    AttestationObject = CBORObject.NewMap().Add("fmt", "testing").Add("attStmt", CBORObject.NewMap()).Add("authData", new byte[0]).EncodeToBytes(),
                    ClientDataJson    = clientDataJson
                },
            };

            var origChallenge = new CredentialCreateOptions
            {
                Attestation            = AttestationConveyancePreference.Direct,
                AuthenticatorSelection = new AuthenticatorSelection
                {
                    AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform,
                    RequireResidentKey      = true,
                    UserVerification        = UserVerificationRequirement.Required,
                },
                Challenge        = challenge,
                ErrorMessage     = "",
                PubKeyCredParams = new List <PubKeyCredParam>()
                {
                    new PubKeyCredParam
                    {
                        Alg  = -7,
                        Type = PublicKeyCredentialType.PublicKey,
                    }
                },
                Rp     = new PublicKeyCredentialRpEntity(rp, rp, ""),
                Status = "ok",
                User   = new Fido2User
                {
                    Name        = "testuser",
                    Id          = Encoding.UTF8.GetBytes("testuser"),
                    DisplayName = "Test User",
                },
                Timeout = 60000,
            };

            IsCredentialIdUniqueToUserAsyncDelegate callback = (args) =>
            {
                return(Task.FromResult(true));
            };

            var lib = new Fido2(new Fido2Configuration()
            {
                ServerDomain = rp,
                ServerName   = rp,
                Origin       = rp,
            });

            var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => lib.MakeNewCredentialAsync(rawResponse, origChallenge, callback));

            Assert.Equal("AttestationResponse is missing type with value 'public-key'", ex.Result.Message);
        }
        public void TestAuthenticatorAttestationResponseUVRequired()
        {
            var challenge = RandomGenerator.Default.GenerateBytes(128);
            var rp        = "https://www.passwordless.dev";
            var acd       = new AttestedCredentialData(("00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-40-FE-6A-32-63-BE-37-D1-01-B1-2E-57-CA-96-6C-00-22-93-E4-19-C8-CD-01-06-23-0B-C6-92-E8-CC-77-12-21-F1-DB-11-5D-41-0F-82-6B-DB-98-AC-64-2E-B1-AE-B5-A8-03-D1-DB-C1-47-EF-37-1C-FD-B1-CE-B0-48-CB-2C-A5-01-02-03-26-20-01-21-58-20-A6-D1-09-38-5A-C7-8E-5B-F0-3D-1C-2E-08-74-BE-6D-BB-A4-0B-4F-2A-5F-2F-11-82-45-65-65-53-4F-67-28-22-58-20-43-E1-08-2A-F3-13-5B-40-60-93-79-AC-47-42-58-AA-B3-97-B8-86-1D-E4-41-B4-4E-83-08-5D-1C-6B-E0-D0").Split('-').Select(c => Convert.ToByte(c, 16)).ToArray());
            var authData  = new AuthenticatorData(
                SHA256.HashData(Encoding.UTF8.GetBytes(rp)),
                AuthenticatorFlags.AT | AuthenticatorFlags.UP,
                0,
                acd
                ).ToByteArray();
            var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
            {
                type      = "webauthn.create",
                challenge = challenge,
                origin    = rp,
            });

            var rawResponse = new AuthenticatorAttestationRawResponse
            {
                Type     = PublicKeyCredentialType.PublicKey,
                Id       = new byte[] { 0xf1, 0xd0 },
                RawId    = new byte[] { 0xf1, 0xd0 },
                Response = new AuthenticatorAttestationRawResponse.ResponseData()
                {
                    AttestationObject = new CborMap {
                        { "fmt", "none" },
                        { "attStmt", new CborMap() },
                        { "authData", authData }
                    }.Encode(),
                ClientDataJson = clientDataJson
                },
            };

            var origChallenge = new CredentialCreateOptions
            {
                Attestation            = AttestationConveyancePreference.Direct,
                AuthenticatorSelection = new AuthenticatorSelection
                {
                    AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform,
                    RequireResidentKey      = true,
                    UserVerification        = UserVerificationRequirement.Required,
                },
                Challenge        = challenge,
                ErrorMessage     = "",
                PubKeyCredParams = new List <PubKeyCredParam>()
                {
                    new PubKeyCredParam(COSE.Algorithm.ES256)
                },
                Rp     = new PublicKeyCredentialRpEntity(rp, rp, ""),
                Status = "ok",
                User   = new Fido2User
                {
                    Name        = "testuser",
                    Id          = Encoding.UTF8.GetBytes("testuser"),
                    DisplayName = "Test User",
                },
                Timeout = 60000,
            };

            IsCredentialIdUniqueToUserAsyncDelegate callback = (args, cancellationToken) =>
            {
                return(Task.FromResult(true));
            };

            IFido2 lib = new Fido2(new Fido2Configuration()
            {
                ServerDomain = rp,
                ServerName   = rp,
                Origins      = new HashSet <string> {
                    rp
                },
            });

            var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => lib.MakeNewCredentialAsync(rawResponse, origChallenge, callback));

            Assert.Equal("User Verified flag not set in authenticator data and user verification was required", ex.Result.Message);
        }
        public void TestAuthenticatorAttestationResponseNoAttestedCredentialData()
        {
            var challenge = RandomGenerator.Default.GenerateBytes(128);
            var rp        = "https://www.passwordless.dev";
            var authData  = new AuthenticatorData(
                SHA256.HashData(Encoding.UTF8.GetBytes(rp)),
                AuthenticatorFlags.UP | AuthenticatorFlags.UV,
                0,
                null
                ).ToByteArray();

            var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
            {
                type      = "webauthn.create",
                challenge = challenge,
                origin    = rp,
            });

            var rawResponse = new AuthenticatorAttestationRawResponse
            {
                Type     = PublicKeyCredentialType.PublicKey,
                Id       = new byte[] { 0xf1, 0xd0 },
                RawId    = new byte[] { 0xf1, 0xd0 },
                Response = new AuthenticatorAttestationRawResponse.ResponseData()
                {
                    AttestationObject = new CborMap {
                        { "fmt", "testing" },
                        { "attStmt", new CborMap() },
                        { "authData", authData }
                    }.Encode(),
                ClientDataJson = clientDataJson
                },
            };

            var origChallenge = new CredentialCreateOptions
            {
                Attestation            = AttestationConveyancePreference.Direct,
                AuthenticatorSelection = new AuthenticatorSelection
                {
                    AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform,
                    RequireResidentKey      = true,
                    UserVerification        = UserVerificationRequirement.Discouraged,
                },
                Challenge        = challenge,
                ErrorMessage     = "",
                PubKeyCredParams = new List <PubKeyCredParam>()
                {
                    new PubKeyCredParam(COSE.Algorithm.ES256)
                },
                Rp     = new PublicKeyCredentialRpEntity(rp, rp, ""),
                Status = "ok",
                User   = new Fido2User
                {
                    Name        = "testuser",
                    Id          = Encoding.UTF8.GetBytes("testuser"),
                    DisplayName = "Test User",
                },
                Timeout = 60000,
            };

            IsCredentialIdUniqueToUserAsyncDelegate callback = (args, cancellationToken) =>
            {
                return(Task.FromResult(true));
            };

            IFido2 lib = new Fido2(new Fido2Configuration()
            {
                ServerDomain = rp,
                ServerName   = rp,
                Origins      = new HashSet <string> {
                    rp
                },
            });

            var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => lib.MakeNewCredentialAsync(rawResponse, origChallenge, callback));

            Assert.Equal("Attestation flag not set on attestation data", ex.Result.Message);
        }
Esempio n. 29
0
        public async Task <JsonResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse attestationResponse)
        {
            try
            {
                // 1. get the options we sent the client
                //var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
                var jsonOptions = await _distributedCache.GetStringAsync(UniqueId);

                if (string.IsNullOrEmpty(jsonOptions))
                {
                    throw new Exception("Can't get CredentialOptions from cache");
                }
                var options = CredentialCreateOptions.FromJson(jsonOptions);

                // 2. Create callback so that lib can verify credential id is unique to this user
                IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
                {
                    var users = await _fido2Storage.GetUsersByCredentialIdAsync(args.CredentialId);

                    if (users.Count > 0)
                    {
                        return(false);
                    }

                    return(true);
                };

                // 2. Verify and make the credentials
                var success = await _lib.MakeNewCredentialAsync(attestationResponse, options, callback);

                // 3. Store the credentials in db
                await _fido2Storage.AddCredentialToUser(options.User, new FidoStoredCredential
                {
                    Username         = options.User.Name,
                    Descriptor       = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
                    PublicKey        = success.Result.PublicKey,
                    UserHandle       = success.Result.User.Id,
                    SignatureCounter = success.Result.Counter,
                    CredType         = success.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = success.Result.Aaguid
                });

                // 4. return "ok" to the client
                var user = await _userManager.GetUserAsync(User);

                if (user == null)
                {
                    return(Json(new CredentialMakeResult {
                        Status = "error", ErrorMessage = $"Unable to load user with ID '{_userManager.GetUserId(User)}'."
                    }));
                }

                await _userManager.SetTwoFactorEnabledAsync(user, true);

                if (await _userManager.CountRecoveryCodesAsync(user) == 0)
                {
                    var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);

                    RecoveryCodes = recoveryCodes.ToArray();
                }

                return(Json(success));
            }
            catch (Exception e)
            {
                return(Json(new CredentialMakeResult {
                    Status = "error", ErrorMessage = FormatException(e)
                }));
            }
        }
Esempio n. 30
0
        public async Task <JsonResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse attestationResponse)
        {
            try
            {
                // 1. get the options we sent the client
                var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
                var options     = CredentialCreateOptions.FromJson(jsonOptions);

                // 2. Create callback so that lib can verify credential id is unique to this user
                // IsCredentialIdUniqueToUserAsyncDelegate callback = async (IsCredentialIdUniqueToUserParams args) =>
                // {
                //   // var users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId);
                //   var users = await _fido2CredentialService.GetUsersByCredentialIdAsync(args.CredentialId);
                //   if (users.Count > 0)
                //     return false;
                //
                //   return true;
                // };
                IsCredentialIdUniqueToUserAsyncDelegate callback = async(IsCredentialIdUniqueToUserParams args) =>
                {
                    // TODO Check if credentials are unique
                    return(true);
                };

                // 2. Verify and make the credentials
                var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback);


                var applicationUser = await _userManager.GetUserAsync(HttpContext.User);

                // Schreibe die Credentials in die Datenbank
                var newFido2Credential = await _fido2CredentialService.AddCredentialToUser(new Fido2Credential()
                {
                    UserId           = applicationUser.Id,
                    Descriptor       = success.Result.CredentialId,
                    PublicKey        = success.Result.PublicKey,
                    UserHandle       = success.Result.User.Id,
                    SignatureCounter = success.Result.Counter,
                    CredType         = success.Result.CredType,
                    RegDate          = DateTime.Now,
                    AaGuid           = success.Result.Aaguid
                });

                // applicationUser.Fido2Credentials.Add(newFido2Credential);
                applicationUser.TwoFactorEnabled = true;
                applicationUser.TwoFactorMethod  = TwoFactorType.Fido2;
                await _userManager.UpdateAsync(applicationUser);

                // TODO Return Databse Entry not just JSON


                // 4. return "ok" to the client
                return(new JsonResult(success));
            }
            catch (Exception e)
            {
                return(new JsonResult(new Fido2.CredentialMakeResult {
                    Status = "error", ErrorMessage = FormatException(e)
                }));
            }
        }