Ejemplo n.º 1
0
        internal static List <PublicKeyCredentialDescriptor> ToCore(this List <MFAPublicKeyCredentialDescriptor> data)
        {
            var creds = new List <PublicKeyCredentialDescriptor>();

            foreach (MFAPublicKeyCredentialDescriptor MFADesc in data)
            {
                PublicKeyCredentialDescriptor res = MFADesc.ToCore();
                creds.Add(res);
            }
            return(creds);
        }
        public async Task <CacheItem> ExecuteAsync(string fido2Payload, CacheItem relatedItem)
        {
            var request = OwnIdSerializer.Deserialize <Fido2LoginRequest>(fido2Payload);

            var storedFido2Info = await _userHandlerAdapter.FindFido2InfoAsync(request.CredentialId);

            if (storedFido2Info == null)
            {
                throw new OwnIdException(ErrorType.UserNotFound);
            }

            var options = new AssertionOptions
            {
                Challenge = Encoding.ASCII.GetBytes(relatedItem.Context),
                RpId      = _configuration.Fido2.RelyingPartyId
            };

            var fidoResponse = new AuthenticatorAssertionRawResponse
            {
                Extensions = new AuthenticationExtensionsClientOutputs(),
                Id         = Base64Url.Decode(request.CredentialId),
                RawId      = Base64Url.Decode(request.CredentialId),
                Response   = new AuthenticatorAssertionRawResponse.AssertionResponse
                {
                    AuthenticatorData = Base64Url.Decode(request.AuthenticatorData),
                    ClientDataJson    = Base64Url.Decode(request.ClientDataJson),
                    Signature         = Base64Url.Decode(request.Signature),
                    UserHandle        = Base64Url.Decode(storedFido2Info.UserId)
                },
                Type = PublicKeyCredentialType.PublicKey
            };

            var result = await _fido2.MakeAssertionAsync(
                fidoResponse,
                options,
                Base64Url.Decode(storedFido2Info.PublicKey),
                storedFido2Info.SignatureCounter,
                args =>
            {
                var storedCredentialId     = Base64Url.Decode(storedFido2Info.CredentialId);
                var storedCredDescriptor   = new PublicKeyCredentialDescriptor(storedCredentialId);
                var credIdValidationResult = storedCredDescriptor.Id.SequenceEqual(args.CredentialId);

                return(Task.FromResult(credIdValidationResult));
            });

            return(await _cacheItemRepository.UpdateAsync(relatedItem.Context, item =>
            {
                item.PublicKey = storedFido2Info.PublicKey;
                item.Fido2SignatureCounter = result.Counter;
                item.Fido2CredentialId = request.CredentialId;
                item.FinishFlow(storedFido2Info.UserId, storedFido2Info.PublicKey);
            }));
        }
        public static PublicKeyCredentialRequestOptions ConvertToPublicKeyCredentialRequestOptions(
            IFido2Client fido2Client,
            ServerPublicKeyCredentialCreationOptionsResponse response,
            bool isUseSelectedPlatformAuthenticator)
        {
            PublicKeyCredentialRequestOptions.Builder builder = new PublicKeyCredentialRequestOptions.Builder();

            builder.SetRpId(response.RpId);

            builder.SetChallenge(ByteUtils.Base64ToByte(response.Challenge));

            ServerPublicKeyCredentialDescriptor[] descriptors = response.AllowCredentials;
            if (descriptors != null)
            {
                List <PublicKeyCredentialDescriptor> descriptorList = new List <PublicKeyCredentialDescriptor>();
                foreach (ServerPublicKeyCredentialDescriptor descriptor in descriptors)
                {
                    List <AuthenticatorTransport> transports = new List <AuthenticatorTransport>();
                    if (descriptor.Transports != null)
                    {
                        try
                        {
                            transports.Add(AuthenticatorTransport.FromValue(descriptor.Transports));
                        }
                        catch (System.Exception e)
                        {
                            Log.Error(Tag, e.Message, e);
                        }
                    }
                    PublicKeyCredentialDescriptor desc = new PublicKeyCredentialDescriptor(
                        PublicKeyCredentialType.PublicKey, ByteUtils.Base64ToByte(descriptor.Id), transports);
                    descriptorList.Add(desc);
                }
                builder.SetAllowList(descriptorList);
            }

            Dictionary <string, Java.Lang.Object> extensions = new Dictionary <string, Java.Lang.Object>();

            if (response.Extensions != null)
            {
                extensions.AddRangeOverride(response.Extensions);
            }
            // Specify a platform authenticator and related extension items. You can specify a platform
            // authenticator or not as needed.
            if (isUseSelectedPlatformAuthenticator)
            {
                UseSelectedPlatformAuthenticator(fido2Client, extensions);
            }
            builder.SetExtensions(extensions);
            builder.SetTimeoutSeconds((Java.Lang.Long)response.Timeout);
            return(builder.Build());
        }
Ejemplo n.º 4
0
        internal static PublicKeyCredentialDescriptor ToCore(this MFAPublicKeyCredentialDescriptor data)
        {
            var creds = new PublicKeyCredentialDescriptor()
            {
                Id   = data.Id,
                Type = (PublicKeyCredentialType)data.Type
            };

            if (data.Transports != null)
            {
                creds.Transports = new AuthenticatorTransport[data.Transports.Length];
                for (int i = 0; i < data.Transports.Length; i++)
                {
                    creds.Transports[i] = (AuthenticatorTransport)data.Transports[i];
                }
            }
            return(creds);
        }
Ejemplo n.º 5
0
        internal async void MakeAssertionResponse(COSE.KeyType kty, COSE.Algorithm alg, COSE.EllipticCurve crv = COSE.EllipticCurve.P256)
        {
            const string rp = "fido2.azurewebsites.net";

            byte[]       rpId         = Encoding.UTF8.GetBytes(rp);
            var          rpIdHash     = SHA256.Create().ComputeHash(rpId);
            var          flags        = AuthenticatorFlags.AT | AuthenticatorFlags.ED | AuthenticatorFlags.UP | AuthenticatorFlags.UV;
            const ushort signCount    = 0xf1d0;
            var          aaguid       = new Guid("F1D0F1D0-F1D0-F1D0-F1D0-F1D0F1D0F1D0");
            var          credentialID = new byte[] { 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, };

            CredentialPublicKey cpk = null;
            ECDsa ecdsa             = null;
            RSA   rsa = null;

            byte[] expandedPrivateKey = null;
            switch (kty)
            {
            case COSE.KeyType.EC2:
            {
                ecdsa = MakeECDsa(alg, crv);
                var ecparams = ecdsa.ExportParameters(true);
                cpk = MakeCredentialPublicKey(kty, alg, crv, ecparams.Q.X, ecparams.Q.Y);
                break;
            }

            case COSE.KeyType.RSA:
            {
                rsa = RSA.Create();
                var rsaparams = rsa.ExportParameters(true);
                cpk = MakeCredentialPublicKey(kty, alg, rsaparams.Modulus, rsaparams.Exponent);
                break;
            }

            case COSE.KeyType.OKP:
            {
                MakeEdDSA(out var privateKeySeed, out var publicKey, out expandedPrivateKey);
                cpk = MakeCredentialPublicKey(kty, alg, COSE.EllipticCurve.Ed25519, publicKey);
                break;
            }
                throw new ArgumentOutOfRangeException(nameof(kty), $"Missing or unknown kty {kty}");
            }

            var acd      = new AttestedCredentialData(aaguid, credentialID, cpk);
            var extBytes = CBORObject.NewMap().Add("testing", true).EncodeToBytes();
            var exts     = new Extensions(extBytes);

            var ad       = new AuthenticatorData(rpIdHash, flags, signCount, acd, exts);
            var authData = ad.ToByteArray();

            var challenge = new byte[128];
            var rng       = RandomNumberGenerator.Create();

            rng.GetBytes(challenge);


            var clientData = new
            {
                Type      = "webauthn.get",
                Challenge = challenge,
                Origin    = rp,
            };
            var clientDataJson = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(clientData));

            var sha = SHA256.Create();
            var hashedClientDataJson = sha.ComputeHash(clientDataJson);

            byte[] data = new byte[authData.Length + hashedClientDataJson.Length];
            Buffer.BlockCopy(authData, 0, data, 0, authData.Length);
            Buffer.BlockCopy(hashedClientDataJson, 0, data, authData.Length, hashedClientDataJson.Length);
            byte[] signature = null;
            switch (kty)
            {
            case COSE.KeyType.EC2:
            {
                signature = ecdsa.SignData(data, CryptoUtils.algMap[(int)alg]);
                break;
            }

            case COSE.KeyType.RSA:
            {
                RSASignaturePadding padding;
                switch (alg)         // https://www.iana.org/assignments/cose/cose.xhtml#algorithms
                {
                case COSE.Algorithm.PS256:
                case COSE.Algorithm.PS384:
                case COSE.Algorithm.PS512:
                    padding = RSASignaturePadding.Pss;
                    break;

                case COSE.Algorithm.RS1:
                case COSE.Algorithm.RS256:
                case COSE.Algorithm.RS384:
                case COSE.Algorithm.RS512:
                    padding = RSASignaturePadding.Pkcs1;
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(alg), $"Missing or unknown alg {alg}");
                }
                signature = rsa.SignData(data, CryptoUtils.algMap[(int)alg], padding);
                break;
            }

            case COSE.KeyType.OKP:
            {
                signature = Ed25519.Sign(data, expandedPrivateKey);
                break;
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(kty), $"Missing or unknown kty {kty}");
            }

            if (kty == COSE.KeyType.EC2)
            {
                signature = EcDsaSigFromSig(signature, ecdsa.KeySize);
            }

            var userHandle = new byte[16];

            rng.GetBytes(userHandle);

            var assertion = new AuthenticatorAssertionRawResponse.AssertionResponse()
            {
                AuthenticatorData = authData,
                Signature         = signature,
                ClientDataJson    = clientDataJson,
                UserHandle        = userHandle,
            };

            var lib = new Fido2(new Fido2Configuration()
            {
                ServerDomain = rp,
                ServerName   = rp,
                Origin       = rp,
            });
            var existingCredentials = new List <PublicKeyCredentialDescriptor>();
            var cred = new PublicKeyCredentialDescriptor
            {
                Type = PublicKeyCredentialType.PublicKey,
                Id   = new byte[] { 0xf1, 0xd0 }
            };

            existingCredentials.Add(cred);

            var options = lib.GetAssertionOptions(existingCredentials, null, null);

            options.Challenge = challenge;
            var response = new AuthenticatorAssertionRawResponse()
            {
                Response = assertion,
                Type     = PublicKeyCredentialType.PublicKey,
                Id       = new byte[] { 0xf1, 0xd0 },
                RawId    = new byte[] { 0xf1, 0xd0 },
            };
            IsUserHandleOwnerOfCredentialIdAsync callback = (args) =>
            {
                return(Task.FromResult(true));
            };
            var res = await lib.MakeAssertionAsync(response, options, cpk.GetBytes(), signCount - 1, callback);
        }
        internal static async Task <AssertionVerificationResult> MakeAssertionResponse(COSE.KeyType kty, COSE.Algorithm alg, COSE.EllipticCurve crv = COSE.EllipticCurve.P256, CredentialPublicKey cpk = null, ushort signCount = 0, ECDsa ecdsa = null, RSA rsa = null, byte[] expandedPrivateKey = null)
        {
            const string rp = "https://www.passwordless.dev";

            byte[] rpId         = Encoding.UTF8.GetBytes(rp);
            var    rpIdHash     = SHA256.Create().ComputeHash(rpId);
            var    flags        = AuthenticatorFlags.AT | AuthenticatorFlags.ED | AuthenticatorFlags.UP | AuthenticatorFlags.UV;
            var    aaguid       = new Guid("F1D0F1D0-F1D0-F1D0-F1D0-F1D0F1D0F1D0");
            var    credentialID = new byte[] { 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, };

            if (cpk == null)
            {
                switch (kty)
                {
                case COSE.KeyType.EC2:
                {
                    if (ecdsa == null)
                    {
                        ecdsa = MakeECDsa(alg, crv);
                    }
                    var ecparams = ecdsa.ExportParameters(true);
                    cpk = MakeCredentialPublicKey(kty, alg, crv, ecparams.Q.X, ecparams.Q.Y);
                    break;
                }

                case COSE.KeyType.RSA:
                {
                    if (rsa == null)
                    {
                        rsa = RSA.Create();
                    }
                    var rsaparams = rsa.ExportParameters(true);
                    cpk = MakeCredentialPublicKey(kty, alg, rsaparams.Modulus, rsaparams.Exponent);
                    break;
                }

                case COSE.KeyType.OKP:
                {
                    byte[] publicKey = null;
                    if (expandedPrivateKey == null)
                    {
                        MakeEdDSA(out var privateKeySeed, out publicKey, out expandedPrivateKey);
                    }

                    cpk = MakeCredentialPublicKey(kty, alg, COSE.EllipticCurve.Ed25519, publicKey);
                    break;
                }
                    throw new ArgumentOutOfRangeException(nameof(kty), $"Missing or unknown kty {kty}");
                }
            }
            var acd      = new AttestedCredentialData(aaguid, credentialID, cpk);
            var extBytes = CBORObject.NewMap().Add("testing", true).EncodeToBytes();
            var exts     = new Extensions(extBytes);

            var ad       = new AuthenticatorData(rpIdHash, flags, (uint)(signCount + 1), acd, exts);
            var authData = ad.ToByteArray();

            var challenge = new byte[128];
            var rng       = RandomNumberGenerator.Create();

            rng.GetBytes(challenge);

            var clientData = new
            {
                Type      = "webauthn.get",
                Challenge = challenge,
                Origin    = rp,
            };
            var clientDataJson = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(clientData));

            var sha = SHA256.Create();
            var hashedClientDataJson = sha.ComputeHash(clientDataJson);

            byte[] data = new byte[authData.Length + hashedClientDataJson.Length];
            Buffer.BlockCopy(authData, 0, data, 0, authData.Length);
            Buffer.BlockCopy(hashedClientDataJson, 0, data, authData.Length, hashedClientDataJson.Length);
            byte[] signature = SignData(kty, alg, data, ecdsa, rsa, expandedPrivateKey);

            var userHandle = new byte[16];

            rng.GetBytes(userHandle);

            var assertion = new AuthenticatorAssertionRawResponse.AssertionResponse()
            {
                AuthenticatorData = authData,
                Signature         = signature,
                ClientDataJson    = clientDataJson,
                UserHandle        = userHandle,
            };

            var lib = new Fido2(new Fido2Configuration()
            {
                ServerDomain = rp,
                ServerName   = rp,
                Origin       = rp,
            });
            var existingCredentials = new List <PublicKeyCredentialDescriptor>();
            var cred = new PublicKeyCredentialDescriptor
            {
                Type = PublicKeyCredentialType.PublicKey,
                Id   = new byte[] { 0xf1, 0xd0 }
            };

            existingCredentials.Add(cred);

            var options = lib.GetAssertionOptions(existingCredentials, null, null);

            options.Challenge = challenge;
            var response = new AuthenticatorAssertionRawResponse()
            {
                Response = assertion,
                Type     = PublicKeyCredentialType.PublicKey,
                Id       = new byte[] { 0xf1, 0xd0 },
                RawId    = new byte[] { 0xf1, 0xd0 },
            };
            IsUserHandleOwnerOfCredentialIdAsync callback = (args) =>
            {
                return(Task.FromResult(true));
            };

            return(await lib.MakeAssertionAsync(response, options, cpk.GetBytes(), signCount, callback));
        }
        public static PublicKeyCredentialCreationOptions ConvertToPublicKeyCredentialCreationOptions(IFido2Client fido2Client,
                                                                                                     ServerPublicKeyCredentialCreationOptionsResponse response)
        {
            PublicKeyCredentialCreationOptions.Builder builder = new PublicKeyCredentialCreationOptions.Builder();

            string name = response.Rp.Name;
            PublicKeyCredentialRpEntity entity = new PublicKeyCredentialRpEntity(name, name, null);

            builder.SetRp(entity);

            string id = response.User.Id;

            try
            {
                builder.SetUser(new PublicKeyCredentialUserEntity(id, System.Text.Encoding.UTF8.GetBytes(id)));
            }
            catch (UnsupportedEncodingException e)
            {
                Log.Error(Tag, e.Message, e);
            }

            builder.SetChallenge(ByteUtils.Base64ToByte(response.Challenge));

            if (response.PubKeyCredParams != null)
            {
                List <PublicKeyCredentialParameters>  parameters = new List <PublicKeyCredentialParameters>();
                ServerPublicKeyCredentialParameters[] serverPublicKeyCredentialParameters = response.PubKeyCredParams;
                foreach (ServerPublicKeyCredentialParameters param in serverPublicKeyCredentialParameters)
                {
                    try
                    {
                        PublicKeyCredentialParameters parameter = new PublicKeyCredentialParameters(
                            PublicKeyCredentialType.PublicKey, Algorithm.FromCode(param.Alg));
                        parameters.Add(parameter);
                    }
                    catch (System.Exception e)
                    {
                        Log.Error(Tag, e.Message, e);
                    }
                }
                builder.SetPubKeyCredParams(parameters);
            }

            if (response.ExcludeCredentials != null)
            {
                List <PublicKeyCredentialDescriptor>  descriptors       = new List <PublicKeyCredentialDescriptor>();
                ServerPublicKeyCredentialDescriptor[] serverDescriptors = response.ExcludeCredentials;
                foreach (ServerPublicKeyCredentialDescriptor desc in serverDescriptors)
                {
                    List <AuthenticatorTransport> transports = new List <AuthenticatorTransport>();
                    if (desc.Transports != null)
                    {
                        try
                        {
                            transports.Add(AuthenticatorTransport.FromValue(desc.Transports));
                        }
                        catch (System.Exception e)
                        {
                            Log.Error(Tag, e.Message, e);
                        }
                    }
                    PublicKeyCredentialDescriptor descriptor = new PublicKeyCredentialDescriptor(
                        PublicKeyCredentialType.PublicKey, ByteUtils.Base64ToByte(desc.Id), transports);
                    descriptors.Add(descriptor);
                }
                builder.SetExcludeList(descriptors);
            }

            Attachment attachment = null;

            if (response.AuthenticatorSelection != null)
            {
                ServerAuthenticatorSelectionCriteria selectionCriteria = response.AuthenticatorSelection;
                if (selectionCriteria.AuthenticatorAttachment != null)
                {
                    try
                    {
                        attachment = Attachment.FromValue(selectionCriteria.AuthenticatorAttachment);
                    }
                    catch (System.Exception e)
                    {
                        Log.Error(Tag, e.Message, e);
                    }
                }

                bool residentKey = selectionCriteria.IsRequireResidentKey;

                UserVerificationRequirement requirement = null;
                if (selectionCriteria.UserVerification != null)
                {
                    try
                    {
                        requirement = UserVerificationRequirement.FromValue(selectionCriteria.UserVerification);
                    }
                    catch (System.Exception e)
                    {
                        Log.Error(Tag, e.Message, e);
                    }
                }

                AuthenticatorSelectionCriteria fido2Selection =
                    new AuthenticatorSelectionCriteria(attachment, (Java.Lang.Boolean)residentKey, requirement);
                builder.SetAuthenticatorSelection(fido2Selection);
            }

            // attestation
            if (response.Attestation != null)
            {
                try
                {
                    AttestationConveyancePreference preference =
                        AttestationConveyancePreference.FromValue(response.Attestation);
                    builder.SetAttestation(preference);
                }
                catch (System.Exception e)
                {
                    Log.Error(Tag, e.Message, e);
                }
            }

            Dictionary <string, Java.Lang.Object> extensions = new Dictionary <string, Java.Lang.Object>();

            if (response.Extensions != null)
            {
                extensions.AddRangeOverride(response.Extensions);
            }

            // Specify a platform authenticator and related extension items. You can specify a platform
            // authenticator or not as needed.
            if (Attachment.Platform.Equals(attachment))
            {
                UseSelectedPlatformAuthenticator(fido2Client, extensions);
            }
            builder.SetExtensions(extensions);
            builder.SetTimeoutSeconds((Java.Lang.Long)response.Timeout);
            return(builder.Build());
        }