День добрый!
Используем Вашу библиотеку, наверное единственное что удалось найти на просторах интернета для подписи с использованием сертификата GOST 3410 в среде Windows. Задача: осуществить взаимодействие с фед. сервисами.
В описании указано:
Требования к формированию токена, подписанного сертификатом ГОСТ Р 34.10-2012
1. Подпись токена (signature) должна быть сформирована в формате pkcs#7. При этом для подписи необходимо оставить только блок SignerInfo и убрать из нее данные сертификата;
2. В заголовке токена (Header) в блок “x5c” не нужно помещать всю цепочку сертификатов так как это влечет за собой превышение лимита длины заголовка запроса.
В итоге получаем при любом раскладе ошибку "GW-059: Неверное значение закодированной формы токена".
Более детальной информации, к сожалению не удается узнать, что не так в формируемом токене.
Окружение:
- сервис на C# (NetFramework 4.7.2)
- нугет библиотеки: GostCryptography 2.0.9.
- Установлен КриптоПРО CSP 4.0.9963
За основу взят пример https://github.com/AlexMAS/GostCryptography/blob/master/Source/GostCryptography.Tests/Pkcs/SignedCmsSignTest.cs
Исходный код (для облегчение и сокращения кода, часть кода убрана, суть остается):
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using GostCryptography.Base;
using GostCryptography.Gost_R3410;
var certStore = new X509Store(StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
var collection = certStore.Certificates;
var searchRes = collection.Find(X509FindType.FindBySerialNumber, serialNumber, false);
var cert = searchRes[0];
var alg = string.Empty;
switch (cert.PublicKey.Oid.Value)
{
case "1.2.643.2.2.19":
alg = "GOST3410-2001";
break;
case "1.2.643.7.1.1.1.1":
alg = "ECGOST3410-2012";
break;
case "1.2.643.7.1.1.1.2":
alg = "ECGOST3410-2012";
break;
}
JwtHeader header = new JwtHeader()
{
{ "alg", alg },
{ "x5c", Convert.ToBase64String(cert.GetRawCertData()) },
};
JwtPayload payload = new JwtPayload()
{
{ "sub", "CD28DB17-8A5E-4DDC-8C0B-0F6C10C9B041" }, /* произвольный гуид */
{ "aud", "http://ya.ru" }, /* произвольный адрес */
{ "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
{ "exp", DateTimeOffset.UtcNow.Add(new TimeSpan(0, 10, 0)).ToUnixTimeSeconds() }
};
JwtSecurityToken token = new JwtSecurityToken(header, payload);
string message = token.EncodedHeader + "." + token.EncodedPayload;
// Создание объекта для подписи сообщения
ContentInfo contentInfo = new ContentInfo(Encoding.UTF8.GetBytes(message));
GostCryptography.Pkcs.GostSignedCms signedCms = new GostCryptography.Pkcs.GostSignedCms(contentInfo);
// Создание объект с информацией о подписчике
CmsSigner cmsSigner = new CmsSigner(cert);
// Включение информации только о конечном сертификате (только для теста)
cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly;
// Создание подписи для сообщения CMS/PKCS#7
signedCms.ComputeSignature(cmsSigner);
// Создание сообщения CMS/PKCS#7
byte[] signature = signedCms.Encode();
var encodedSignature = Microsoft.IdentityModel.Tokens.Base64UrlEncoder.Encode(signature);
var jwtToken = $"{message}.{encodedSignature}";
/* в итоге получаем токен из трех составляющих
token.EncodedHeader + "." + token.EncodedPayload + "." + encodedSignature */
И при обращении, при любом раскладе получаем ошибку:
"GW-059: Неверное значение закодированной формы токена".
Что конкретно не так в токене, выяснить не удается.
В описании имеется фраза: "и убрать из нее данные сертификата;" - пробовали делать signedCms.Certificates.Clear(); перед вызовом signedCms.Encode();, не помогает.
Не можем понять что может быть. Может у нас что-то не так недонастроено, или какой-то строки кода не хватает.
Или всё же пытаться выяснять что не так в формате.
Подскажите пожалуйста, что может быть, по какому пути идти ?