Страницы

Поиск по вопросам

воскресенье, 22 декабря 2019 г.

реализация ЕСИА на сайте

#c_sharp #авторизация #oauth #аутентификация


Добрый день! Встал вопрос прикрутить авторизацию на сайте через есиа (Госуслуги). 
Наверняка кто-то уже проделывал это! Помогите пожалуйста, я от этого очень далека,
а сделать надо...

В общем, имеется сайт на ASP.NET (c#, Windows Forms).

Выбранный тип аутентификации - OAuth 2.0 и OpenID Connect 1.0.

Уже, как указано, на сайте минкомсвязи сформировали заявку на подключение к тестовой
среде ЕСИА. Заявку одобрили, прислали документ с инструкцией и 3 файла. В инструкии
как таковых шагов нет, только логины и пароли для входа на госуслуги тестовые и описание
того, что должно прийти в ответ. 

Файлы типа .rar - по инструкции это якобы контейнеры с ключами для ЭЦП.
например, архив EsiaTest.006.rar содержит такие файлы:


header.key 
masks.key
masks2.key
name.key
primary.key
primary2.key


Все параметры для авторизации в принципе понятны, кроме как раз подписи.
Вот как раз с формированием ЭЦП у меня проблемы.

В документе сказано формировать ее так:


  Подпись запроса в формате PKCS#7 detached signature в кодировке UTF-8 от значений
четырех параметров HTTP–запроса: scope, timestamp, clientId, state (они у меня есть).
Подпись должна быть закодирована в формате base64 url safe. Используемый для проверки
подписи сертификат должен быть предварительно зарегистрирован в ЕСИА и привязан к учетной
записи системы-клиента в ЕСИА. ЕСИА поддерживает сертификаты в формате X.509. ЕСИА
поддерживает алгоритмы формирования электронной подписи RSA с длиной ключа 2048 и алгоритмом
криптографического хэширования SHA-256, а также алгоритм электронной подписи ГОСТ Р
34.10-2001 и алгоритм криптографического хэширования ГОСТ Р 34.11-94.


Помогите сформировать эту подпись! Как все это реализовать на c# ?
Заранее благодарю
    


Ответы

Ответ 1



Шаги по интеграции вы вряд ли где-то найдете. Есть только методические рекомендации и регламент работы с ЕСИА, но адекватного описания процедуры "как это сделать на C#" там нет :) То, что вам прислали вместе с ответом на заявку — это просто примеры разных тестовых аккаунтов для отладки работы, т.е. это НИКАК НЕ СВЯЗАНО с подписью ваших запросов к ЕСИА. Вот команды которыми мы генерирует правильный сертификат: openssl req -nodes -sha256 -newkey rsa:2048 -keyout secret.key -out request.csr -subj /C=RU/ST=Rostov-na-Donu/L=city/O=COMPANY\/emailAddress=EMAIL@site.ru/ openssl x509 -req -sha256 -days 3650 -in request.csr -signkey secret.key -out cert.crt -extfile /etc/ssl/openssl.cnf -extensions v3_ca openssl x509 -in cert.crt -text Соответственно в нужные места нужно подставить правильные данные о компании почту и т.п. это команда работает под линуксом при этом в файле /etc/ssl/openssl.cnf надо добавить(изменить) следующую секцию: [ v3_ca ] # Extensions for a typical CA # PKIX recommendation. keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment extendedKeyUsage = emailProtection, clientAuth subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer в результате вы получите работающий сертификат cert.crt и ключ secret.key Но это будет только начало. Там еще вагон и маленькая тележка нюансов по части обмена данными с ЕСИА. Вот тут есть готовое решение, в т.ч. и на C#: esia.pro Оно платное, но помимо готовой реализации там еще проконсультируют по процессу интеграции и оргвопросам.

Ответ 2



У нас подпись заработала как-то так: public static byte[] Sign(X509Certificate2 certificate, byte[] data) { if (data == null) throw new ArgumentNullException("data"); if (certificate == null) throw new ArgumentNullException("certificate"); // setup the data to sign ContentInfo content = new ContentInfo(data); SignedCms signedCms = new SignedCms(content, true); CmsSigner signer = new CmsSigner(certificate); var sha256 = new Oid("2.16.840.1.101.3.4.2.1", "sha256"); signer.DigestAlgorithm = sha256; // create the signature signedCms.ComputeSignature(signer); var signature = signedCms.Encode(); return signature; } С base64 там всё не очевидно: Convert.ToBase64String не подходит, не достаточно точно реализует стандарт. Использовал вот такой метод: public static string Base64UrlEncode(byte[] arg) { string s = Convert.ToBase64String(arg); // Regular base64 encoder s = s.Split('=')[0]; // Remove any trailing '='s s = s.Replace('+', '-'); // 62nd char of encoding s = s.Replace('/', '_'); // 63rd char of encoding return s; } Проверка их подписи - это очередной ребус. Можно предположить, что это процесс обратный процессу подписания, т.е. как-то так: public static bool ValidateCmsSignature(byte[] data, byte[] signature, X509Certificate2 certificate) { bool result = false; if (data == null) throw new ArgumentNullException("data"); if (signature == null) throw new ArgumentNullException("signature"); if (certificate == null) throw new ArgumentNullException("certificate"); // setup the data to sign ContentInfo content = new ContentInfo(data); SignedCms signedCms = new SignedCms(content, true); try { signedCms.Decode(signature); signedCms.CheckSignature(new X509Certificate2Collection(certificate), true); result = true; } catch (Exception ex) { var msg = ex.Message; } return result; } И этот метод работает для проверки нашей подписи, но не подходит для их подписи. А почему? Если мы сначала формируем текстовую строку, потом создаем отсоединенную подпись по ней, и потом всё это кодируем в base64, то они формируют два JSON'а: HEADER и PAYLOAD, потом кодируют их по отдельности в base64, и вот потом формируют подпись по строке HEADERbase64.PAYLOADbase64. А потом уже и подпись кодируют в base64. Итого, метод для проверки их подписи выглядит как-то так: public static bool ValidateSignature(byte[] data, byte[] signature, X509Certificate2 certificate) { bool result = false; using (var csp = (RSACryptoServiceProvider) certificate.PublicKey.Key) { using (var hasher = new SHA256Managed()) { var hash = hasher.ComputeHash(data); string id = CryptoConfig.MapNameToOID("SHA256"); bool isDataok = csp.VerifyData(data, id, signature); bool isHashOk = csp.VerifyHash(hash, id, signature); // можно ещё так //RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(csp); //rsaDeformatter.SetHashAlgorithm("SHA256"); //bool isHashOk2 = rsaDeformatter.VerifySignature(hash, signature); result = isDataok && isHashOk; } } return result; }

Ответ 3



А вообще уже есть в NuGet полезнейшая библиотечка, с которой всё становится легче: https://www.nuget.org/packages?q=esia.net В наши времена первопроходимцев так не баловали :))

Комментариев нет:

Отправить комментарий