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}"); } }
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}"); } }
internal CredentialPublicKey MakeCredentialPublicKey(COSE.KeyType kty, COSE.Algorithm alg, byte[] n, byte[] e) { return(MakeCredentialPublicKey(kty, alg, null, null, null, n, e)); }
internal CredentialPublicKey MakeCredentialPublicKey(COSE.KeyType kty, COSE.Algorithm alg, COSE.EllipticCurve crv, byte[] x) { return(MakeCredentialPublicKey(kty, alg, crv, x, null, null, null)); }
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); }
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]; }
internal void Add(COSE.KeyCommonParameter key, COSE.KeyType value) { items.Add(new(new CborInteger((int)key), new CborInteger((int)value))); }
internal CborObject this[COSE.KeyType key] => GetValue((long)key);