CryptoPro / libcore

43 stars 0 forks source link

Не проходит проверка Raw подписи JWT токена от ЕСИА #45

Closed VitaliyNazarov closed 10 months ago

VitaliyNazarov commented 11 months ago

Помогите разобраться. Пытаюсь проверить Raw подпись JWT токена полученого от ЕСИА в результате прохождения OIDC flow.

Окружение

Данные

Код

Получение сертификата из хранилища - тут все ОК

    private static string SerialNumberTest = "014018b300ffafd593465c5c2de413c849";
    private static X509Certificate2 GetCert()
    {
        using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
        {
            store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
            var certs = store.Certificates.Find(X509FindType.FindBySerialNumber, SerialNumberTest, false);
            if (certs.Count == 0)
                throw new EsiaServiceException("Certificate is not found");
            return certs[0];    
        }   
    }

Проверки подписи 1 - при любом reverseSignature

    private static void VerifySignature1(string accessToken, bool reverseSignature)
    {
        var parts = accessToken.Split('.');
        var message = Encoding.UTF8.GetBytes($"{parts[0]}.{parts[1]}");
        var sign = Base64UrlEncoder.DecodeBytes(parts[2]);
        if (reverseSignature)
            Array.Reverse(sign, 0, sign.Length);

        var certificate = GetCert();
        using (var csp = certificate.GetGost3410_2012_256PublicKey())
        {
            var result = csp.VerifyData(message, sign, CpHashAlgorithmName.Gost3411_2012_256);
            if (!result)
                throw new Exception("Invalid signature");
        }
    }

Проверки подписи 2 - при любом reverseSignature

    private static void VerifySignature2(string accessToken, bool reverseSignature)
    {
        var parts = accessToken.Split('.');
        var message = Encoding.UTF8.GetBytes($"{parts[0]}.{parts[1]}");
        var sign = Base64UrlEncoder.DecodeBytes(parts[2]);
        if (reverseSignature)
            Array.Reverse(sign, 0, sign.Length);

        var certificate = GetCert();
        using (var csp = certificate.GetGost3410_2012_256PublicKey())
        {
            using (var hasher = Gost3411_2012_256.Create())
            {
                var hash = hasher.ComputeHash(message);
                var formatter = new Gost2012_256SignatureDeformatter(csp);
                formatter.SetHashAlgorithm(nameof(Gost3411_2012_256));
                var ret = formatter.VerifySignature(hash, sign);
                Assert.False(ret);                
            }
        }
    }
Fasjeit commented 10 months ago

Успешно проверили приложенный токен на сертификате с серийным номером 014018b300ffafd593465c5c2de413c849 (TESIA GOST 2012.cer из архива).

 LibCore.Initializer.Initialize();

 var jwt = "eyJ2ZXIiOjEsInR5cCI6IkpXVCIsInNidCI6ImFjY2VzcyIsImFsZyI6IkdPU1QzNDEwXzIwMTJfMjU2In0.eyJuYmYiOjE3MDEyNTQ1NzUsInNjb3BlIjoidXNyX3JlZ19jeHQ_b2lkPTEwMDAzMjg2ODYgZW1haWw_b2lkPTEwMDAzMjg2ODYgb3BlbmlkIHVzcl9hdnQ_b2lkPTEwMDAzMjg2ODYgdXNyX29yZz9vaWQ9MTAwMDMyODY4NiBmdWxsbmFtZT9vaWQ9MTAwMDMyODY4NiBtb2JpbGU_b2lkPTEwMDAzMjg2ODYiLCJpc3MiOiJodHRwOlwvXC9lc2lhLXBvcnRhbDEudGVzdC5nb3N1c2x1Z2kucnVcLyIsInVybjplc2lhOnNpZCI6ImExNTEwY2IyLTAxMTItZjJmNS0zZGI2LTZiYzc1ZGI0MGUwZSIsInVybjplc2lhOnNial9pZCI6MTAwMDMyODY4NiwiZXhwIjoxNzAxMjU4MTc1LCJpYXQiOjE3MDEyNTQ1NzUsImNsaWVudF9pZCI6IkNUUFJGX1JVIn0.cz8DPKHZvTsF__reCBDsZ4ZPxehs4qanCmiJjJr2slzrWTmv_HkScguPGU5NDlyJrxi25Tv8rcqfg7YM0PKsDg";
 var parts = jwt.Split('.');
 if (parts.Length != 3)
 {
     throw new ArgumentException("Cannot parse jws signature");
 }

 var payloadBytes = Encoding.UTF8.GetBytes($"{parts[0]}.{parts[1]}");
 var signatureBytes = Base64UrlEncoder.DecodeBytes(parts[2]);

 using (var certg = new X509Certificate2(@"TESIA GOST 2012.cer"))
 {
     var gost = certg.PublicKey.Key as Gost3410_2012_256CryptoServiceProvider;
     var valResult = gost.VerifyData(payloadBytes, signatureBytes, CpHashAlgorithmName.Gost3411_2012_256);
 }