Answer the question
In order to leave comments, you need to log in
How to sign a string for ESIA?
Hello!
There is a task to authorize the user on the site through ESIA.
There is a GOST 2012 certificate issued through CryptoPRO.
Installed on the computer
КриптоПРО CSP
КриптоПРО .NET
КриптоПРО .NET SDK
using System;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.IO;
namespace Samples.CMS
{
class DetachedSignature
{
[STAThread]
static void Main(string[] args)
{
// Проверка корректности переданных параметров.
if (args.Length < 1)
{
Console.WriteLine("CMS.DetachedSignature <cert-subject>");
return;
}
String signerName = args[0];
// Исходное сообщение.
const String msg = "Это сообщение, которое будет подписано.";
Console.WriteLine("{0}Исходное сообщение (длина {1}): {2} ",
Environment.NewLine, msg.Length, msg);
// Переводим исходное сообщение в массив байтов.
Encoding unicode = Encoding.Unicode;
byte[] msgBytes = unicode.GetBytes(msg);
Console.WriteLine("{0}{0}------------------------------",
Environment.NewLine);
Console.WriteLine(" Поиск сертификата ");
Console.WriteLine("------------------------------{0}",
Environment.NewLine);
// Получаем сертификат ключа подписи;
// он будет использоваться для получения
// секретного ключа подписи.
X509Certificate2 signerCert = GetSignerCert(signerName);
Console.WriteLine("{0}{0}------------------------------",
Environment.NewLine);
Console.WriteLine(" На стороне отправителя");
Console.WriteLine("------------------------------{0}",
Environment.NewLine);
byte[] encodedSignature = SignMsg(msgBytes, signerCert);
File.WriteAllBytes("signature.bin", encodedSignature);
Console.WriteLine("{0}{0}------------------------------",
Environment.NewLine);
Console.WriteLine(" На стороне получателя ");
Console.WriteLine("------------------------------{0}",
Environment.NewLine);
// При проверка detached подписи передаем и само сообщение
if (VerifyMsg(msgBytes, encodedSignature))
{
Console.WriteLine("{0}Сообщение проверено.",
Environment.NewLine);
}
else
{
Console.WriteLine("{0}Ошибка при проверке сообщения.",
Environment.NewLine);
}
}
// Открываем хранилище 'My' и ищем сертификат
// для подписи сообщения.
static X509Certificate2 GetSignerCert(string signerName)
{
// Открываем хранилище My.
X509Store storeMy = new X509Store(StoreName.My,
StoreLocation.CurrentUser);
storeMy.Open(OpenFlags.ReadOnly);
// Отображаем сертификаты для удобства работы
// с примером.
Console.WriteLine("Найдены сертификаты следующих субъектов " +
"в хранилище {0}:", storeMy.Name);
foreach (X509Certificate2 cert in storeMy.Certificates)
{
Console.WriteLine("\t{0}", cert.SubjectName.Name);
}
// Ищем сертификат для подписи.
X509Certificate2Collection certColl =
storeMy.Certificates.Find(X509FindType.FindBySubjectName,
signerName, false);
Console.WriteLine(
"Найдено {0} сертификат(ов) в хранилище {1} для субъекта {2}",
certColl.Count, storeMy.Name, signerName);
// Проверяем, что нашли требуемый сертификат
if (certColl.Count == 0)
{
Console.WriteLine(
"Сертификат для данного примера не найден " +
"в хранилище. Выберите другой сертификат для подписи. ");
return null;
}
storeMy.Close();
// Если найдено более одного сертификата,
// возвращаем первый попавщийся.
return certColl[0];
}
// Подписываем сообщение секретным ключем.
static byte[] SignMsg(
Byte[] msg,
X509Certificate2 signerCert)
{
// Создаем объект ContentInfo по сообщению.
// Это необходимо для создания объекта SignedCms.
ContentInfo contentInfo = new ContentInfo(msg);
// Создаем объект SignedCms по только что созданному
// объекту ContentInfo.
// SubjectIdentifierType установлен по умолчанию в
// IssuerAndSerialNumber.
// Свойство Detached устанавливаем явно в true, таким
// образом сообщение будет отделено от подписи.
SignedCms signedCms = new SignedCms(contentInfo, true);
// Определяем подписывающего, объектом CmsSigner.
CmsSigner cmsSigner = new CmsSigner(signerCert);
// Подписываем CMS/PKCS #7 сообение.
Console.Write("Вычисляем подпись сообщения для субъекта " +
"{0} ... ", signerCert.SubjectName.Name);
signedCms.ComputeSignature(cmsSigner);
Console.WriteLine("Успешно.");
// Кодируем CMS/PKCS #7 подпись сообщения.
return signedCms.Encode();
}
// Проверяем SignedCms сообщение и возвращаем Boolean
// значение определяющее результат проверки.
static bool VerifyMsg(Byte[] msg,
byte[] encodedSignature)
{
// Создаем объект ContentInfo по сообщению.
// Это необходимо для создания объекта SignedCms.
ContentInfo contentInfo = new ContentInfo(msg);
// Создаем SignedCms для декодирования и проверки.
SignedCms signedCms = new SignedCms(contentInfo, true);
// Декодируем подпись
signedCms.Decode(encodedSignature);
// Перехватываем криптографические исключения, для
// возврата о false значения при некорректности подписи.
try
{
// Проверяем подпись. В данном примере не
// проверяется корректность сертификата подписавшего.
// В рабочем коде, скорее всего потребуется построение
// и проверка корректности цепочки сертификата.
Console.Write("Проверка подписи сообщения ... ");
signedCms.CheckSignature(true);
Console.WriteLine("Успешно.");
}
catch (System.Security.Cryptography.CryptographicException e)
{
Console.WriteLine("Функция VerifyMsg возбудила исключение: {0}",
e.Message);
Console.WriteLine("Проверка PKCS #7 сообщения завершилась " +
"неудачно. Возможно сообщене, подпись, или " +
"соподписи модифицированы в процессе передачи или хранения. " +
"Подписавший или соподписавшие возможно не те " +
"за кого себя выдают. Достоверность и/или целостность " +
"сообщения не гарантируется. ");
return false;
}
return true;
}
}
}
error_description: ESIA-007005: The client is not authorized to request an access token using this method.
state: 35805cc9-8b2f-4f85-b30b-8f3e88d215ca
error: unauthorized_client
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question