예제 #1
0
        internal CredentialPublicKey MakeCredentialPublicKey(COSE.KeyType kty, COSE.Algorithm alg, COSE.EllipticCurve?crv, byte[] x, byte[] y, byte[] n, byte[] e)
        {
            var cpk = CBORObject.NewMap();

            cpk.Add(COSE.KeyCommonParameter.KeyType, kty);
            cpk.Add(COSE.KeyCommonParameter.Alg, alg);
            switch (kty)
            {
            case COSE.KeyType.EC2:
                cpk.Add(COSE.KeyTypeParameter.X, x);
                cpk.Add(COSE.KeyTypeParameter.Y, y);
                cpk.Add(COSE.KeyTypeParameter.Crv, crv);
                break;

            case COSE.KeyType.RSA:
                cpk.Add(COSE.KeyTypeParameter.N, n);
                cpk.Add(COSE.KeyTypeParameter.E, e);
                break;

            case COSE.KeyType.OKP:
                cpk.Add(COSE.KeyTypeParameter.X, x);
                cpk.Add(COSE.KeyTypeParameter.Crv, crv);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(kty), kty, "Invalid COSE key type");
            }
            return(new CredentialPublicKey(cpk));
        }
            internal byte[] SignData(COSE.KeyType kty, COSE.Algorithm alg, COSE.EllipticCurve crv)
            {
                ECDsa ecdsa      = null;
                RSA   rsa        = null;
                Key   privateKey = null;

                byte[] expandedPrivateKey = null, publicKey = null;

                switch (kty)
                {
                case COSE.KeyType.EC2:
                {
                    ecdsa = MakeECDsa(alg, crv);
                    break;
                }

                case COSE.KeyType.RSA:
                {
                    rsa = RSA.Create();
                    break;
                }

                case COSE.KeyType.OKP:
                {
                    MakeEdDSA(out var privateKeySeed, out publicKey, out expandedPrivateKey);
                    privateKey = Key.Import(SignatureAlgorithm.Ed25519, expandedPrivateKey, KeyBlobFormat.RawPrivateKey);
                    break;
                }
                    throw new ArgumentOutOfRangeException(nameof(kty), $"Missing or unknown kty {kty}");
                }

                return(SignData(kty, alg, crv, ecdsa, rsa, privateKey, publicKey));
            }
        public CredentialPublicKey(X509Certificate2 cert, COSE.Algorithm alg)
        {
            var keyAlg = cert.GetKeyAlgorithm();

            _type = CoseKeyTypeFromOid[keyAlg];
            _alg  = alg;
            _cpk  = new CborMap
            {
                { COSE.KeyCommonParameter.KeyType, _type },
                { COSE.KeyCommonParameter.Alg, _alg }
            };

            if (_type is COSE.KeyType.RSA)
            {
                var keyParams = cert.GetRSAPublicKey() !.ExportParameters(false);
                _cpk.Add(COSE.KeyTypeParameter.N, keyParams.Modulus !);
                _cpk.Add(COSE.KeyTypeParameter.E, keyParams.Exponent !);
            }
            else if (_type is COSE.KeyType.EC2)
            {
                var ecDsaPubKey = cert.GetECDsaPublicKey() !;
                var keyParams   = ecDsaPubKey.ExportParameters(false);

                if (keyParams.Curve.Oid.FriendlyName is "secP256k1")
                {
                    _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P256K);
                }

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    if (keyParams.Curve.Oid.FriendlyName !.Equals(ECCurve.NamedCurves.nistP256.Oid.FriendlyName, StringComparison.Ordinal))
                    {
                        _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P256);
                    }

                    else if (keyParams.Curve.Oid.FriendlyName.Equals(ECCurve.NamedCurves.nistP384.Oid.FriendlyName, StringComparison.Ordinal))
                    {
                        _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P384);
                    }

                    else if (keyParams.Curve.Oid.FriendlyName.Equals(ECCurve.NamedCurves.nistP521.Oid.FriendlyName, StringComparison.Ordinal))
                    {
                        _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P521);
                    }
                }
                else
                {
                    if (keyParams.Curve.Oid.Value !.Equals(ECCurve.NamedCurves.nistP256.Oid.Value, StringComparison.Ordinal))
                    {
                        _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P256);
                    }
            internal byte[] SignData(COSE.KeyType kty, COSE.Algorithm alg, COSE.EllipticCurve curve, ECDsa ecdsa = null, RSA rsa = null, Key expandedPrivateKey = null, byte[] publicKey = null)
            {
                switch (kty)
                {
                case COSE.KeyType.EC2:
                {
                    var ecparams = ecdsa.ExportParameters(true);
                    _credentialPublicKey = MakeCredentialPublicKey(kty, alg, curve, ecparams.Q.X, ecparams.Q.Y);
                    var signature = ecdsa.SignData(_attToBeSigned, CryptoUtils.HashAlgFromCOSEAlg((int)alg));
                    return(EcDsaSigFromSig(signature, ecdsa.KeySize));
                }

                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}");
                    }

                    var rsaparams = rsa.ExportParameters(true);
                    _credentialPublicKey = MakeCredentialPublicKey(kty, alg, rsaparams.Modulus, rsaparams.Exponent);
                    return(rsa.SignData(_attToBeSigned, CryptoUtils.HashAlgFromCOSEAlg((int)alg), padding));
                }

                case COSE.KeyType.OKP:
                {
                    _credentialPublicKey = MakeCredentialPublicKey(kty, alg, COSE.EllipticCurve.Ed25519, publicKey);
                    return(SignatureAlgorithm.Ed25519.Sign(expandedPrivateKey, _attToBeSigned));
                }

                default:
                    throw new ArgumentOutOfRangeException(nameof(kty), $"Missing or unknown kty {kty}");
                }
            }
예제 #5
0
        public CredentialPublicKey(X509Certificate2 cert, int alg)
        {
            _cpk = CBORObject.NewMap();
            var keyAlg = cert.GetKeyAlgorithm();

            _type = CoseKeyTypeFromOid[keyAlg];
            _alg  = (COSE.Algorithm)alg;
            _cpk.Add(COSE.KeyCommonParameter.KeyType, _type);
            _cpk.Add(COSE.KeyCommonParameter.Alg, alg);
            if (COSE.KeyType.RSA == _type)
            {
                var keyParams = cert.GetRSAPublicKey().ExportParameters(false);
                _cpk.Add(COSE.KeyTypeParameter.N, keyParams.Modulus);
                _cpk.Add(COSE.KeyTypeParameter.E, keyParams.Exponent);
            }
            if (COSE.KeyType.EC2 == _type)
            {
                var ecDsaPubKey = (ECDsaCng)cert.GetECDsaPublicKey();
                var keyParams   = ecDsaPubKey.ExportParameters(false);

                if (keyParams.Curve.Oid.FriendlyName.Equals(ECCurve.NamedCurves.nistP256.Oid.FriendlyName))
                {
                    _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P256);
                }

                if (keyParams.Curve.Oid.FriendlyName.Equals("secP256k1"))
                {
                    _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P256K);
                }

                if (keyParams.Curve.Oid.FriendlyName.Equals(ECCurve.NamedCurves.nistP384.Oid.FriendlyName))
                {
                    _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P384);
                }

                if (keyParams.Curve.Oid.FriendlyName.Equals(ECCurve.NamedCurves.nistP521.Oid.FriendlyName))
                {
                    _cpk.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P521);
                }

                _cpk.Add(COSE.KeyTypeParameter.X, keyParams.Q.X);
                _cpk.Add(COSE.KeyTypeParameter.Y, keyParams.Q.Y);
            }
        }
        internal static byte[] SignData(COSE.KeyType kty, COSE.Algorithm alg, byte[] data, ECDsa ecdsa = null, RSA rsa = null, byte[] expandedPrivateKey = null)
        {
            switch (kty)
            {
            case COSE.KeyType.EC2:
            {
                var signature = ecdsa.SignData(data, CryptoUtils.HashAlgFromCOSEAlg((int)alg));
                return(EcDsaSigFromSig(signature, ecdsa.KeySize));
            }

            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}");
                }
                return(rsa.SignData(data, CryptoUtils.HashAlgFromCOSEAlg((int)alg), padding));
            }

            case COSE.KeyType.OKP:
            {
                Key privateKey = Key.Import(SignatureAlgorithm.Ed25519, expandedPrivateKey, KeyBlobFormat.RawPrivateKey);
                return(SignatureAlgorithm.Ed25519.Sign(privateKey, data));
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(kty), $"Missing or unknown kty {kty}");
            }
        }
예제 #7
0
 internal CredentialPublicKey MakeCredentialPublicKey(COSE.KeyType kty, COSE.Algorithm alg, byte[] n, byte[] e)
 {
     return(MakeCredentialPublicKey(kty, alg, null, null, null, n, e));
 }
예제 #8
0
 internal CredentialPublicKey MakeCredentialPublicKey(COSE.KeyType kty, COSE.Algorithm alg, COSE.EllipticCurve crv, byte[] x)
 {
     return(MakeCredentialPublicKey(kty, alg, crv, x, null, null, null));
 }
예제 #9
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);
        }
예제 #10
0
 public CredentialPublicKey(CBORObject cpk)
 {
     _cpk  = cpk;
     _type = (COSE.KeyType)cpk[CBORObject.FromObject(COSE.KeyCommonParameter.KeyType)].AsInt32();
     _alg  = (COSE.Algorithm)cpk[CBORObject.FromObject(COSE.KeyCommonParameter.Alg)].AsInt32();
 }
        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 CredentialPublicKey(CborMap cpk)
 {
     _cpk  = cpk;
     _type = (COSE.KeyType)(int) cpk[COSE.KeyCommonParameter.KeyType];
     _alg  = (COSE.Algorithm)(int) cpk[COSE.KeyCommonParameter.Alg];
 }
예제 #13
0
 internal void Add(COSE.KeyCommonParameter key, COSE.KeyType value)
 {
     items.Add(new(new CborInteger((int)key), new CborInteger((int)value)));
 }
예제 #14
0
 internal CborObject this[COSE.KeyType key] => GetValue((long)key);