Аутентификация Webauthn с помощью Windows Hello через c #

ОБНОВЛЕНИЕ: ===========

Возникла очень похожая проблема с Elliptical Curve, как и с RSA. VarifyData всегда возвращает false.

        byte[] data = new byte[authData.Length + hashValClientData.Length];
        Buffer.BlockCopy(authData, 0, data, 0, authData.Length);
        Buffer.BlockCopy(hashValClientData, 0, data, authData.Length, hashValClientData.Length);

        byte[] sig = Convert.FromBase64String(assertion.Signature);

        if (pubKey.kty == "EC")
        {
            var keyType = new byte[] { 0x45, 0x43, 0x53, 0x31 }; // BCRYPT_ECDSA_PUBLIC_P256_MAGIC {E, C, S, 1}
            var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 }; // Key length 32
            byte[] keyImport = new byte [72];
            Buffer.BlockCopy(keyType, 0, keyImport, 0, 4);
            Buffer.BlockCopy(keyLength, 0, keyImport, 4, 4);
            Buffer.BlockCopy(Convert.FromBase64String(pubKey.x), 0, keyImport, 8, 32);
            Buffer.BlockCopy(Convert.FromBase64String(pubKey.y), 0, keyImport, 40, 32);

            try
            {
                using (ECDsaCng dsa = new ECDsaCng(CngKey.Import(keyImport, CngKeyBlobFormat.EccPublicBlob)))
                {
                    dsa.HashAlgorithm = CngAlgorithm.Sha256;
                    if (dsa.VerifyData(data, sig))
                    {
                        Console.WriteLine("The signature is valid.");
                    }
                    else
                    {
                        Console.WriteLine("The signature is not valid.");
                        return FAIL_STATUS;
                    }
                }
            }
            catch (Exception e)
            {
                return FAIL_STATUS;
            }
        } 

Объект ECDsaCng и CngKey действительны, но метод VerifyData всегда возвращает false. Что-то не так с моими данными?

ClientDataJSON имеет экранирование косой черты из Android EC1, но не из Windows RSA.

===================

Я пытаюсь использовать C # для проверки учетных данных FIDO2 / WebAuthn, возвращаемых из Javascript navigator.credentials.get (). Аутентификатором здесь является Windows Hello (PIN-код). Метод VerifySignature продолжает возвращать недействительную подпись независимо от того, что я делаю. Я использую неправильный алгоритм RSA? Base64, когда этого быть не должно? Любые идеи?

Код Javascript: -

return navigator.credentials.get({
        publicKey: getAssertionOptions
    }).then(rawAssertion => {
        var assertion = {
            id: base64encode(rawAssertion.rawId),
            clientDataJSON: arrayBufferToString(rawAssertion.response.clientDataJSON),
            userHandle: base64encode(rawAssertion.response.userHandle),
            signature: base64encode(rawAssertion.response.signature),
            authenticatorData: base64encode(rawAssertion.response.authenticatorData)
        };

Код C #: -

creds.Id = tempDB.Id;
creds.PublicKeyJwk = tempDB.PublicKeyJwk;

byte[] hashValClientData = _hash.ComputeHash(Encoding.Latin1.GetBytes(assertion.ClientDataJSON));

RSA rsa = RSA.Create();
PublicKey pubKey;
try
{
    pubKey = JsonConvert.DeserializeObject<PublicKey>(creds.PublicKeyJwk);
}
catch (Exception ex)
{
    return FAIL_STATUS;
}

RSAParameters keyInfo = new RSAParameters();
keyInfo.Modulus = Encoding.Latin1.GetBytes(Base64Decode(pubKey.n));
keyInfo.Exponent = Encoding.Latin1.GetBytes(Base64Decode(pubKey.e));
rsa.ImportParameters(keyInfo);
RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA256");
byte[] sig = Encoding.Latin1.GetBytes(Base64Decode(assertion.Signature));
if (rsaDeformatter.VerifySignature(hashValClientData, sig))
{
    Console.WriteLine("The signature is valid.");
}
else
{
    Console.WriteLine("The signature is not valid.");
}

        public static string Base64Encode(string plainText)
        {
            var plainTextBytes = Encoding.Latin1.GetBytes(plainText);
            return Convert.ToBase64String(plainTextBytes);
        }
        public static string Base64Decode(string base64EncodedData)
        {
            string paddedString = base64EncodedData;
            int padding = base64EncodedData.Length % 4;
            if (padding > 0 && padding < 3)
            {
                paddedString += "==".Substring(0, padding);
            }
            var base64EncodedBytes = Convert.FromBase64String(paddedString);
            return Encoding.Latin1.GetString(base64EncodedBytes);
        }

Вывод консоли браузера: -

=== ответ Утверждение === test.html: 211 Идентификатор (base64): gtCDzIXzuh0ZlblqiyMFf7f0 / TS2m2a8sLvbj3CtERo = test.html: 211 clientDataJSON: {Тип: webauthn.get, вызов: ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmxlSEFpT2pFMk1UUTFNRFV6TURJc0ltbHpjeUk2SWxSbGMzUXVZMjl0SWl3aVlYVmtJam9pVkdWemRDNWpiMjBpZlEuUXdYVUdob3FQM1RGckhGV2pOOHNyZWVadFpMM2gtaUVpZk9jTWlzbHQxVQ, Происхождение: HTTPS: // локальный: 44362, crossOrigin: false, other_keys_can_be_added_here: не сравнивать clientDataJSON с шаблоном. } Test.html: 211 userHandle (base64): c29tZS51c2VyLmlk test.html: 211 подпись (base64): Gd0x / 28tLTKba9 / LRA + 7riJ4XygPgfAjwdVw3h / fxisWSU8OLbcfqu6K5bIFspnPrsTyA6xD9I + 5Sq / BAOalcAJCy46 / 39swTPF6 + 76F8Hx5GFNcXusMZw6PQZpEqALZkifF936hTBXCoVrYcl9NZ5 / jjd9zpFhSN90Ht / WEAl4DrvgnZ / NQa2klCpm4anDaZoYDcv9SykqtUv / CHNAtpSYgcfA8XVcDGG3ieefw1rii6g6chgTNfwhctIiqSkCBrLECavVUrbT6UpF + R2nIgexCyT8dKe8gVxvNaUeFnltSSkleOo / GUHzisseFjTow + R9yo4og / tuuS9PSWTR8WA == test.html: 211 AuthenticatorData (base64): SZYN5YgOjGh0NBcPZHZgW4 / krrmihjLHmVzzuoMdl2MFAAAAAQ ==


person McMurphy    schedule 28.02.2021    source источник
comment
Latin1.GetBytes (Base64Decode ()) выглядит странно. Base64 уже производит байты. Вместо того, чтобы писать свои собственные, просто используйте Convert.FromBase64String   -  person bartonjs    schedule 28.02.2021


Ответы (1)


Могут быть и другие проблемы, но самая большая проблема заключается в том, что вы пытаетесь проверить подпись по хешу clientDataJSON. На самом деле это должно быть двоичное объединение AuthenticatorData и хешированного clientDataJSON.

Из https://www.w3.org/TR/webauthn/#sctn-verifying-assertion, шаг 20:

Используя credentialPublicKey, убедитесь, что sig является действительной подписью над двоичной конкатенацией authData и хэша.

Учитывая то, что у вас есть, должно работать что-то вроде этого:

    var authData = Convert.FromBase64String(assertion.authenticatorData);
    byte[] hashValClientData = _hash.ComputeHash(assertion.ClientDataJSON);

    byte[] data = new byte[authData.Length + hashValClientData.Length];
    Buffer.BlockCopy(authData, 0, data, 0, authData.Length);
    Buffer.BlockCopy(hashValClientData, 0, data, authData.Length, hashValClientData.Length);

    var rsa = RSA.Create();
    rsa.ImportParameters(
        new RSAParameters()
        {
            Modulus = Convert.FromBase64String(pubKey.n),
            Exponent = Convert.FromBase64String(pubKey.e),
        }
    );

    byte[] sig = Convert.FromBase64String(assertion.Signature);
    if (rsa.VerifyData(data, sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
    {
        Console.WriteLine("The signature is valid.");
    }
    else
    {
        Console.WriteLine("The signature is not valid.");
    }

В этом проекте может быть интересующий вас код: https://github.com/abergs/fido2-net-lib

person aseigler    schedule 08.03.2021
comment
Хорошо подмечено! Похоже, я недостаточно разбирался в crypto.createVerify, чтобы перевести код с github. com / MicrosoftEdge / webauthnsample / blob / master / fido.js Я попробую. - person McMurphy; 09.03.2021
comment
Ты чемпион! @aseigler Но похоже, что вам не приходилось вручную заполнять свой Base64, благодаря Microsoft: - Ввод не является допустимой строкой Base-64, поскольку он содержит символ, отличный от базового 64, более двух символов заполнения или недопустимый символ среди символов заполнения. :-( - person McMurphy; 11.03.2021
comment
Это может помочь: stackoverflow.com / questions / 61719894 / - person aseigler; 12.03.2021
comment
Привет, @aseigler, извини, что вернулся к колодцу, но надеюсь, что ты тоже сможешь помочь с моей проблемой EC? Ура Ричард - person McMurphy; 15.03.2021
comment
EC2 отличается, подпись должна быть преобразована для работы с библиотеками .NET, см. github.com/abergs/fido2-net-lib/blob/. Отсюда вы можете создать объект ECDsa следующим образом: github.com/abergs/fido2-net-lib/blob/ А затем проверьте подпись следующим образом: github.com/abergs/fido2-net-lib/blob/ - person aseigler; 16.03.2021
comment
Это EC1, а не EC2 (см. Правку к моему исходному вопросу выше). Это происходит с телефона Samsung / Android. Ваши ссылки не кажутся полностью актуальными? - person McMurphy; 16.03.2021
comment
Ах, формат подписи. Попался! - person McMurphy; 16.03.2021