Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Наши способы организации безопасного удалённого доступа к рабочим местам и корпоративным ресурсам
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline eisy  
#1 Оставлено : 9 июля 2020 г. 16:01:15(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Добрый день.
Мне требуется подписывать данные по гост 34.10 -2012.
libphpcades поставил по инструкции http://cpdn.cryptopro.ru...tent/cades/phpcades.html

Имеется сертификат на сервере.
он успешно устанавливается по команде
sudo /opt/cprocsp/bin/amd64/certmgr -inst -store uMy -file cert.cer

по команде sudo /opt/cprocsp/bin/amd64/certmgr -list -store uMy он есть

но вот так ничего не находит

Цитата:
$store = new CPStore();
$store->Open(CURRENT_USER_STORE, "My", STORE_OPEN_READ_ONLY);

$certs = $store->get_Certificates();
var_dump($certs);


Цитата:
object(CPCertificates)#2 (0) {
}


Не помогает и пример использования, с поиском моего сертификата http://cpdn.cryptopro.ru...tent/cades/phpcades.html через CERTIFICATE_FIND_SHA1_HASH

Цитата:
<?php
//Вспомогательные функции предварительной инициализации
function SetupStore($location, $name, $mode)
{
$store = new CPStore();
$store->Open($location, $name, $mode);
return $store;
}

function SetupCertificates($location, $name, $mode)
{
$store = SetupStore($location, $name, $mode);
$certs = $store->get_Certificates();
return $certs;

}

function SetupCertificate($location, $name, $mode,
$find_type, $query, $valid_only,
$number)
{
$certs = SetupCertificates($location, $name, $mode);
if(!is_null($find_type))
{
$certs = $certs->Find($find_type, $query, $valid_only);
return $certs->Item($number);
}
else
{
$cert = $certs->Item($number);
return $cert;
}
}



$content = "test content";
$tsp_addres = "http://testca.cryptopro.ru/tsp/tsp.srf";
$cert = SetupCertificate(CURRENT_USER_STORE, "My", STORE_OPEN_READ_ONLY,
CERTIFICATE_FIND_SHA1_HASH, "42ee7ec1137ecd4468daa7caff0e345f86da346a", 0,
1);

if (!$cert)
{
printf("Certificate not found\n");
return;
}

$signer = new CPSigner();
$signer->set_TSAAddress($tsp_addres);
$signer->set_Certificate($cert);

$sd = new CPSignedData();
$sd->set_Content($content);

$sm = $sd->Sign($signer, 0, STRING_TO_UCS2LE);
printf("Signature is:\n");
printf($sm);
printf("\n");
$sd->Verify($sm, 0, VERIFY_SIGNATURE_ONLY);
printf("Verify OK\n");

?>

Ответ
Цитата:
PHP Fatal error: Uncaught exception 'Exception' with message 'Internal error. (0x8009200B)' in /var/www/html/info.php:56
Stack trace:
#0 /var/www/html/info.php(56): CPSignedData->Sign(Object(CPSigner), 0, 0)
#1 {main}
thrown in /var/www/html/info.php on line 56
Offline Александр Лавник  
#2 Оставлено : 9 июля 2020 г. 16:52:01(UTC)
Александр Лавник

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 30.06.2016(UTC)
Сообщений: 2,061
Мужчина
Российская Федерация

Сказал «Спасибо»: 32 раз
Поблагодарили: 476 раз в 455 постах
Здравствуйте.

1) Для возможности создания подписи необходимо устанавливать сертификат с привязкой к соответствующему ключевому контейнеру.

Если сертификат есть в ключевом контейнере, то сделать это можно, например, следующей командой:

Код:
/opt/cprocsp/bin/amd64/csptest -absorb -certs -autoprov


Если сертификата нет внутри ключевого контейнера, то сначала нужно вывести имя нужного ключевого контейнера командой:

Код:
/opt/cprocsp/bin/amd64/csptest -keys -enum -verifyc -fqcn


А затем уже установить сертификат, указав файл сертификата и ключевой контейнер в команде:

Код:
/opt/cprocsp/bin/amd64/certmgr -inst -cont 'contname' -file cert.cer


где contname - имя нужного ключевого контейнера из вывода предыдущей команды (в команде нужно взять в одинарные кавычки).

Все команды требуется запускать от нужного пользователя.

2) Установка сертификата должна выполняться от того пользователя, под которым запускается скрипт.

3) Какая у Вас конечная цель?

Какую именно подпись нужно создать?

Возможно, phphcades вообще такое не умеет или можно сделать это проще (через вызов из PHP-кода консольных утилиты).
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Александр Лавник за этот пост.
eisy оставлено 09.07.2020(UTC)
Offline eisy  
#3 Оставлено : 9 июля 2020 г. 17:04:17(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Автор: Александр Лавник Перейти к цитате


1-2.
Спасибо, контейнер и хранилище (store) это одно и то же? в коде ведь мы указываем хранилище, а не контейнер.
SetupCertificate(CURRENT_USER_STORE, "My") ?

вот что вернуло /opt/cprocsp/bin/amd64/csptest -keys -enum -verifyc -fqcn
не очень понял где здесь контейнер?
Цитата:

CSP (Type:80) v4.0.9019 KC1 Release Ver:4.0.9963 OS:Linux CPU:AMD64 FastCode:READY:AVX.
AcquireContext: OK. HCRYPTPROV: 9140867
OK.
Total: SYS: 0.010 sec USR: 0.030 sec UTC: 0.210 sec
[ErrorCode: 0x00000000]



3.
Мне необходимо подписывать набор данных в base64 для работы с сервисом приема. Сервиса приема с ИС ООВО


Цитата:
Verify signarure представляет закодированную в Base64 ЭЦП по ГОСТ 34.10-2012

Signarure представляет собой подписанный хэш данных, кодированный в base64.
Расчёт хеш-суммы, 256 бит - ГОСТ Р 34.11-2012.
Расчет подписи, 256 бит - ГОСТ Р 34.10-2012.
Подпись передается без контейнера. Подписываемая последовательность
представляет собой конкатенацию части Header в Base64 и Payload в Base64 разделенных символом точка.
Разделитель "." входит в последовательность. Для JWT отправляемых в метод "/api/token/info"
"HeaderBase64..signatureBase64" "." входит в последовательность пример : "HeaderBase64." .
Также, следуют учитывать особенность работы ГОСТ алгоритмов:
При использовании API КриптоПро, для формирования хеша используется функция CryptHashData,
после формирования подписи функцией CryptSignHash, полученный набор байт следует
инвертировать перед кодированием в base64. Т.е. в base64 кодируется массив байт "задом-наперед"
от полученного функцией CryptSignHash.


насколько я вижу из описания COM обьектов, нужный мне алгоритм есть? https://cpdn.cryptopro.r...33fe4815d569f2ca026.html
CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256_HMAC

Отредактировано пользователем 9 июля 2020 г. 17:09:29(UTC)  | Причина: Не указана

Offline Александр Лавник  
#4 Оставлено : 9 июля 2020 г. 17:18:06(UTC)
Александр Лавник

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 30.06.2016(UTC)
Сообщений: 2,061
Мужчина
Российская Федерация

Сказал «Спасибо»: 32 раз
Поблагодарили: 476 раз в 455 постах
Нет, хранилище сертификатов и ключевой контейнер - это разные сущности.

Упрощенно говоря, хранилище сертификатов содержит сертификаты и информацию о привязке к ключевым контейнерам этих сертификатов.

Ключевой контейнер - сущность, содержащая закрытый ключ, и хранящаяся на ключевом носителе (на Linux это: жесткий диск, флеш-накопитель, USB-токен, смарт-карта).

По созданию нужной Вам подписи (сырая raw подпись 64 байта) Вы можете или использовать вызов утилиты csptest (исходные данные и подпись во внешних файлах) или при использовании phpcades сделать по аналогии с примером по ссылке.
Техническую поддержку оказываем тут
Наша база знаний
Offline eisy  
#5 Оставлено : 9 июля 2020 г. 21:25:20(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Автор: Александр Лавник Перейти к цитате
Нет, хранилище сертификатов и ключевой контейнер - это разные сущности.

Упрощенно говоря, хранилище сертификатов содержит сертификаты и информацию о привязке к ключевым контейнерам этих сертификатов.

Ключевой контейнер - сущность, содержащая закрытый ключ, и хранящаяся на ключевом носителе (на Linux это: жесткий диск, флеш-накопитель, USB-токен, смарт-карта).

По созданию нужной Вам подписи (сырая raw подпись 64 байта) Вы можете или использовать вызов утилиты csptest (исходные данные и подпись во внешних файлах) или при использовании phpcades сделать по аналогии с примером по ссылке.


Не очень понял, как создать ключевой контейнер на сервере

команда /opt/cprocsp/bin/amd64/csptest -keys -enum -verifyc -fqcn
возвращает

Цитата:

CSP (Type:80) v4.0.9019 KC1 Release Ver:4.0.9963 OS:Linux CPU:AMD64 FastCode:READY:AVX.
AcquireContext: OK. HCRYPTPROV: 9140867
OK.
Total: SYS: 0.010 sec USR: 0.030 sec UTC: 0.210 sec
[ErrorCode: 0x00000000]

я так понимаю контейнеров у меня нет

UPD:
Нашел данную проблему для Мак https://www.cryptopro.ru...&m=112348#post112348
так понимаю тоже переносить в /var/opt/cprocsp/keys ? у меня там сейчас две папки с пользователями

Отредактировано пользователем 9 июля 2020 г. 21:35:30(UTC)  | Причина: Не указана

Offline Александр Лавник  
#6 Оставлено : 9 июля 2020 г. 22:15:06(UTC)
Александр Лавник

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 30.06.2016(UTC)
Сообщений: 2,061
Мужчина
Российская Федерация

Сказал «Спасибо»: 32 раз
Поблагодарили: 476 раз в 455 постах
Автор: eisy Перейти к цитате
Автор: Александр Лавник Перейти к цитате
Нет, хранилище сертификатов и ключевой контейнер - это разные сущности.

Упрощенно говоря, хранилище сертификатов содержит сертификаты и информацию о привязке к ключевым контейнерам этих сертификатов.

Ключевой контейнер - сущность, содержащая закрытый ключ, и хранящаяся на ключевом носителе (на Linux это: жесткий диск, флеш-накопитель, USB-токен, смарт-карта).

По созданию нужной Вам подписи (сырая raw подпись 64 байта) Вы можете или использовать вызов утилиты csptest (исходные данные и подпись во внешних файлах) или при использовании phpcades сделать по аналогии с примером по ссылке.


Не очень понял, как создать ключевой контейнер на сервере

команда /opt/cprocsp/bin/amd64/csptest -keys -enum -verifyc -fqcn
возвращает

Цитата:

CSP (Type:80) v4.0.9019 KC1 Release Ver:4.0.9963 OS:Linux CPU:AMD64 FastCode:READY:AVX.
AcquireContext: OK. HCRYPTPROV: 9140867
OK.
Total: SYS: 0.010 sec USR: 0.030 sec UTC: 0.210 sec
[ErrorCode: 0x00000000]

я так понимаю контейнеров у меня нет

UPD:
Нашел данную проблему для Мак https://www.cryptopro.ru...&m=112348#post112348
так понимаю тоже переносить в /var/opt/cprocsp/keys ? у меня там сейчас две папки с пользователями

Да, на Linux ключевые контейнеры на жестком диске должны находиться в той же директории, что и на macOS (как и на всех *nix).

Если у Вас есть ключевой контейнер для Вашего личного сертификата, то Вы можете перенести его в соответствующую директорию на жестком диске для нужного пользователя.

Затем установить сертификата с привязкой к ключевому контейнеру, как описано ранее.
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Александр Лавник за этот пост.
eisy оставлено 11.07.2020(UTC)
Offline eisy  
#7 Оставлено : 11 июля 2020 г. 12:18:09(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Для истории может кому то пригодится
Успешно установил сертификат в ключевой контейнер (перенеся папку с 6 файлами .key в /var/opt/cprocsp/keys/ваш_пользователь)
далее команда
Цитата:
/opt/cprocsp/bin/amd64/csptest -absorb -certs -provtype 80 -provider "Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider"

Смотрим полное название нашего контейнера
Цитата:
/opt/cprocsp/bin/amd64/csptest -keys -enum -verifyc -fqcn

P.S. оно в виде
Цитата:
\\.\HDIMAGE\te-85627756-e110-4860-ac2c-4afc5e22a2cf


Устанавливаем наш сертификат в него
Потребуется пароль от контейнера
Цитата:
/opt/cprocsp/bin/amd64/certmgr -inst -store uMy -cont '\\.\HDIMAGE\te-85627756-e110-4860-ac2c-4afc5e22a2cf' -file certificate.cer


Затем при попытке тестовой подписи может появиться
Цитата:
PHP Fatal error: Uncaught exception 'Exception' with message 'A certificate chain processed correctly, but terminated in a root certificate which is not trusted by the trust provider (0x800B0109)' in /var/www/html/info.php:56
Stack trace:
#0 /var/www/html/info.php(56): CPSignedData->Sign(Object(CPSigner), 0, 0)
#1 {main}
thrown in /var/www/html/info.php on line 56


поставил отсюда сертификаты для хранилища root успешно http://testca2012.cryptopro.ru/ui/
Цитата:
/opt/cprocsp/bin/amd64/certmgr -inst -store uroot -file rootca.cer
/opt/cprocsp/bin/amd64/certmgr -inst -store uroot -file subca.cer


и соответственно проверяем чтоб запрос шел на нужный нам путь
Цитата:
http://testca2012.cryptopro.ru/tsp/tsp.srf


сейчас буду разбираться как использовать нужный мне алгоритм
Расчёт хеш-суммы, 256 бит - ГОСТ Р 34.11-2012.
Расчет подписи, 256 бит - ГОСТ Р 34.10-2012.

PS.
Прописываем чтоб не требовался ключ

Цитата:
/opt/cprocsp/sbin/amd64/cpconfig -ini "\\LOCAL\\KeyDevices\\passwords\\HDIMAGE\\te-85627.000" -add string passwd ЦИФРЫ_КЛЮЧА

Отредактировано пользователем 13 июля 2020 г. 16:29:06(UTC)  | Причина: Не указана

Offline eisy  
#8 Оставлено : 11 июля 2020 г. 13:39:51(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
del

Отредактировано пользователем 13 июля 2020 г. 16:29:45(UTC)  | Причина: Не указана

Offline eisy  
#9 Оставлено : 13 июля 2020 г. 14:23:06(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
del

Отредактировано пользователем 13 июля 2020 г. 16:29:24(UTC)  | Причина: Не указана

Offline eisy  
#10 Оставлено : 13 июля 2020 г. 16:32:57(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Всё вроде победил,
Цитата:
<?php

//Вспомогательные функции предварительной инициализации
function SetupStore($location, $name, $mode)
{
$store = new CPStore();
$store->Open($location, $name, $mode);
return $store;
}

function SetupCertificates($location, $name, $mode)
{
$store = SetupStore($location, $name, $mode);
$certs = $store->get_Certificates();
return $certs;

}

function SetupCertificate($location, $name, $mode,
$find_type, $query, $valid_only,
$number)
{
$certs = SetupCertificates($location, $name, $mode);

if(!is_null($find_type))
{
$certs = $certs->Find($find_type, $query, $valid_only);
return $certs->Item($number);
}
else
{
$cert = $certs->Item($number);
return $cert;
}
}

function CreateSignature($oCertificate, $oHashedData) {

$signer = new CPRawSignature();
$sRawSignature = $signer->SignHash($oHashedData, $oCertificate);

return $sRawSignature;
}




$content = "test content";
$tsp_addres = "http://testca2012.cryptopro.ru/tsp/tsp.srf";
$cert = SetupCertificate(2, "My", STORE_OPEN_READ_ONLY,
CERTIFICATE_FIND_SHA1_HASH, "5ff6a0ad2a3431c4a72007d68e2bac5dc4c2c7b9", 0,
1);

if (!$cert)
{
printf("Certificate not found\n");
return;
}

$hd = new CPHashedData();

$hd->set_Algorithm(CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256);

$hd->Hash($content);

$hash_val = CreateSignature($cert,$hd);
var_dump($hash_val);
die();


Так возвращает подпись, просьба знатоков подсказать правильно ли я интерпретировал
Цитата:
Расчёт хеш-суммы, 256 бит - ГОСТ Р 34.11-2012.
Расчет подписи, 256 бит - ГОСТ Р 34.10-2012.


Сам сертификат вот
Цитата:
Signature Algorithm : ГОСТ Р 34.11-2012/34.10-2012 256 бит
PublicKey Algorithm : ГОСТ Р 34.10-2012 (512 bits)
Not valid before : 10/07/2020 09:29:40 UTC
Not valid after : 10/10/2020 09:39:40 UTC
PrivateKey Link : Yes
Container : HDIMAGE\\te-85627.000\7800
Provider Name : Crypto-Pro GOST R 34.10-2012 KC1 CSP

Отредактировано пользователем 13 июля 2020 г. 16:36:09(UTC)  | Причина: Не указана

Offline Александр Лавник  
#11 Оставлено : 13 июля 2020 г. 16:43:09(UTC)
Александр Лавник

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 30.06.2016(UTC)
Сообщений: 2,061
Мужчина
Российская Федерация

Сказал «Спасибо»: 32 раз
Поблагодарили: 476 раз в 455 постах
Здравствуйте.

Похоже, что реализация корректна.

Вам необходимо еще учесть, что полученную сырую подпись необходимо побайтово перевернуть:

Цитата:
При использовании API КриптоПро, для формирования хеша используется функция CryptHashData,
после формирования подписи функцией CryptSignHash, полученный набор байт следует
инвертировать перед кодированием в base64. Т.е. в base64 кодируется массив байт "задом-наперед"
от полученного функцией CryptSignHash.
Техническую поддержку оказываем тут
Наша база знаний
Offline Александр Лавник  
#12 Оставлено : 13 июля 2020 г. 21:14:13(UTC)
Александр Лавник

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 30.06.2016(UTC)
Сообщений: 2,061
Мужчина
Российская Федерация

Сказал «Спасибо»: 32 раз
Поблагодарили: 476 раз в 455 постах
Всё-таки необходимо кое-что изменить в Вашем коде:

Код:
$hd->Hash($content);

нужно заменить на:

Код:
$hd->set_DataEncoding(BASE64_TO_BINARY);
$hd->hash(base64_encode($content));
Техническую поддержку оказываем тут
Наша база знаний
Offline eisy  
#13 Оставлено : 23 июля 2020 г. 13:14:51(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Автор: Александр Лавник Перейти к цитате
Всё-таки необходимо кое-что изменить в Вашем коде:

Код:
$hd->Hash($content);

нужно заменить на:

Код:
$hd->set_DataEncoding(BASE64_TO_BINARY);
$hd->hash(base64_encode($content));


В общем ждал пока получу нужные контейнеры, до этого все с тестовым сертификатом пробовал.

Код и так и так пробовал, сырую подпись инвертировал, но взаимодействовать с нужным мне сервисом не удалось :(
Даже не знаю что ещё бы попробовать

Цитата:
{"Error":"Проверка ЭЦП завершилась с результатом 80090006: Invalid Signature.. Signarure представляет собой подписанный хэш данных, кодированный в base64.Расчёт хеш-суммы, 256 бит - ГОСТ Р 34.11-2012. Расчет подписи, 256 бит - ГОСТ Р 34.10-2012. Подпись передается без контейнера. Подписываемая последовательность представляет собой конкатенацию части Header и Payload разделенных символом точка. Разделитель \".\" входит в последовательность. Для JWT отправляемых в метод \"/api/token/info\" \"Header..signature\" \".\" входит в последовательность пример : \"Header.\" . Также, следуют учитывать особенность работы ГОСТ алгоритмов: При использовании API КриптоПро, для формирования хеша используется функция CryptHashData, после формирования подписи функцией CryptSignHash, полученный набор байт следует инвертировать перед кодированием в base64. Т.е. в base64 кодируется массив байт \"задом-наперед\" от полученного функцией CryptSignHash.","ErrorCode":5001}

Отредактировано пользователем 23 июля 2020 г. 13:15:30(UTC)  | Причина: Не указана

Offline Александр Лавник  
#14 Оставлено : 23 июля 2020 г. 13:29:23(UTC)
Александр Лавник

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 30.06.2016(UTC)
Сообщений: 2,061
Мужчина
Российская Федерация

Сказал «Спасибо»: 32 раз
Поблагодарили: 476 раз в 455 постах
Автор: eisy Перейти к цитате
Автор: Александр Лавник Перейти к цитате
Всё-таки необходимо кое-что изменить в Вашем коде:

Код:
$hd->Hash($content);

нужно заменить на:

Код:
$hd->set_DataEncoding(BASE64_TO_BINARY);
$hd->hash(base64_encode($content));


В общем ждал пока получу нужные контейнеры, до этого все с тестовым сертификатом пробовал.

Код и так и так пробовал, сырую подпись инвертировал, но взаимодействовать с нужным мне сервисом не удалось :(
Даже не знаю что ещё бы попробовать

Цитата:
{"Error":"Проверка ЭЦП завершилась с результатом 80090006: Invalid Signature.. Signarure представляет собой подписанный хэш данных, кодированный в base64.Расчёт хеш-суммы, 256 бит - ГОСТ Р 34.11-2012. Расчет подписи, 256 бит - ГОСТ Р 34.10-2012. Подпись передается без контейнера. Подписываемая последовательность представляет собой конкатенацию части Header и Payload разделенных символом точка. Разделитель \".\" входит в последовательность. Для JWT отправляемых в метод \"/api/token/info\" \"Header..signature\" \".\" входит в последовательность пример : \"Header.\" . Также, следуют учитывать особенность работы ГОСТ алгоритмов: При использовании API КриптоПро, для формирования хеша используется функция CryptHashData, после формирования подписи функцией CryptSignHash, полученный набор байт следует инвертировать перед кодированием в base64. Т.е. в base64 кодируется массив байт \"задом-наперед\" от полученного функцией CryptSignHash.","ErrorCode":5001}

Здравствуйте.

Raw подпись инвертировали побайтово перед преобразованием в Base64?

Где можно ознакомится с требованиями к нужной Вам подписи?
Техническую поддержку оказываем тут
Наша база знаний
Offline eisy  
#15 Оставлено : 23 июля 2020 г. 15:51:44(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Автор: Александр Лавник Перейти к цитате
Автор: eisy Перейти к цитате
Автор: Александр Лавник Перейти к цитате
Всё-таки необходимо кое-что изменить в Вашем коде:

Код:
$hd->Hash($content);

нужно заменить на:

Код:
$hd->set_DataEncoding(BASE64_TO_BINARY);
$hd->hash(base64_encode($content));


В общем ждал пока получу нужные контейнеры, до этого все с тестовым сертификатом пробовал.

Код и так и так пробовал, сырую подпись инвертировал, но взаимодействовать с нужным мне сервисом не удалось :(
Даже не знаю что ещё бы попробовать

Цитата:
{"Error":"Проверка ЭЦП завершилась с результатом 80090006: Invalid Signature.. Signarure представляет собой подписанный хэш данных, кодированный в base64.Расчёт хеш-суммы, 256 бит - ГОСТ Р 34.11-2012. Расчет подписи, 256 бит - ГОСТ Р 34.10-2012. Подпись передается без контейнера. Подписываемая последовательность представляет собой конкатенацию части Header и Payload разделенных символом точка. Разделитель \".\" входит в последовательность. Для JWT отправляемых в метод \"/api/token/info\" \"Header..signature\" \".\" входит в последовательность пример : \"Header.\" . Также, следуют учитывать особенность работы ГОСТ алгоритмов: При использовании API КриптоПро, для формирования хеша используется функция CryptHashData, после формирования подписи функцией CryptSignHash, полученный набор байт следует инвертировать перед кодированием в base64. Т.е. в base64 кодируется массив байт \"задом-наперед\" от полученного функцией CryptSignHash.","ErrorCode":5001}

Здравствуйте.

Raw подпись инвертировали побайтово перед преобразованием в Base64?

Где можно ознакомится с требованиями к нужной Вам подписи?



Да подпись инвертировал, спецификация суперсервиса вот, 4-6 страницы
Specifikacija servisa vzaimodejjstvija (API) v_2_1 (1) 18 ijunja 2020.docx (184kb) загружен 2 раз(а).

Цитата:
Verify signarure
Verify signarure представляет закодированную в Base64 ЭЦП по ГОСТ 34.10-2012 см. выше соответствующий цвет. Подписываемая последовательность представляет собой конкатенацию части Header и Payload разделенных символом точка.
Открытый ключ сертификата, которым осуществляется подпись помещается в виде x509 сертификата закодированного в Base64 в Header в поле cert64.


Ошибка именно с сигнатурой, сертификат в x509 гружу, структура запроса тоже корректная, по ней ошибок нет

Отредактировано пользователем 23 июля 2020 г. 15:53:22(UTC)  | Причина: Не указана

Offline eisy  
#16 Оставлено : 31 июля 2020 г. 11:03:49(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Пообщался с тех поддержкой, они говорят вот чего.

Цитата:
По представленным кускам кода , предполагается, что в используемой обертке
над CriptoPRO , вызывается функция, производящая операцию, отличную от
требуемой.


Скинули пример, у них подпись такая получается
Цитата:
_I\F3Aq Gn!3լAIwpg x{]rhމr6gb#

У меня, по процедурам выше явно другой формат
Цитата:
FC3054F94299653582DFA04F998E8C06FCD5A929CA5B64861A5528C4A84AC97AA8C1911641EDF7D2195B435727C97015AA56AEEEF06B9E92C79FDDBAB09918E5


Ещё скинули файл на Си, но я его не особо знаю, как и функции в библиотеке крипто про, чтоб понять как сделать аналогично


Цитата:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>

#include <WinCryptEx.h>

#define GR3411LEN 64

#define LANGUAGE 1033

char* Signature(BYTE* bdata, DWORD lenData) {
char* result = NULL;

BYTE* sigData = NULL;
BYTE * tempSig = NULL;
PCCERT_CONTEXT pCertCtx = NULL;
HCERTSTORE hCertStore = NULL;
CERT_PUBLIC_KEY_INFO* pubKeyInfo = NULL;


HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;

if(!CryptAcquireContext(
&hProv,
"\\\\.\\HDIMAGE\\test",
NULL,
PROV_GOST_2012_256,
CRYPT_SILENT)) {
goto Finish;
}

DWORD kiLen = 0;
if(CryptExportPublicKeyInfo(hProv,AT_KEYEXCHANGE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, &kiLen))
{
pubKeyInfo = (CERT_PUBLIC_KEY_INFO*)malloc(kiLen);
if(!CryptExportPublicKeyInfo(hProv,AT_KEYEXCHANGE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pubKeyInfo, &kiLen)) {
goto Finish;
}
}
else {
goto Finish;
}

if(pubKeyInfo == NULL) {
goto Finish;
}

if(!CryptCreateHash(hProv, CALG_GR3411_2012_256, 0, 0, &hHash)) {
goto Finish;
}

if(!CryptHashData(hHash, bdata, lenData, 0)) {
goto Finish;
}

DWORD sigLen = 0;
if(!CryptSignHash(
hHash,
AT_KEYEXCHANGE,
NULL,
0,
NULL,
&sigLen)) {
goto Finish;
}

sigData = (BYTE*)malloc(sigLen*sizeof(BYTE));
if(!CryptSignHash(
hHash,
AT_KEYEXCHANGE,
NULL,
0,
sigData,
&sigLen)) {
goto Finish;
}

tempSig = (BYTE*) malloc(sigLen);
DWORD j;
for(j = 0; j < sigLen; j++)
{
tempSig[j] = sigData[sigLen - j - 1];
}

DWORD nLenOut=0;
char* tmpString = NULL;
if(CryptBinaryToString(
tempSig, sigLen,
CRYPT_STRING_BASE64,
NULL, &nLenOut)
) {
tmpString = (char*)malloc(nLenOut*sizeof(char));
if(!CryptBinaryToString(tempSig, sigLen, CRYPT_STRING_BASE64, tmpString, &nLenOut)) {
goto Finish;
}
}
else {
goto Finish;
}

result = tmpString;

Finish:
if(hHash) CryptDestroyHash(hHash);
if(hProv) CryptReleaseContext(hProv, 0);
if(tempSig) free(tempSig);
if(bdata) free(bdata);
if(sigData) free(sigData);


hHash = 0;
hProv = 0;

return result;
}

char* Verify(BYTE* bData, DWORD dataLen,BYTE* bcert, DWORD lenCert, BYTE* bSign, DWORD signLen){
char* result = NULL;

BYTE* tempSig = NULL;
PCCERT_CONTEXT ppCertCtx = NULL;

HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
if(!CryptAcquireContext(
&hProv,
NULL,
NULL,
PROV_GOST_2012_256,
CRYPT_VERIFYCONTEXT))
{
goto Finish;
}

if(!CryptCreateHash(hProv, CALG_GR3411_2012_256, 0, 0, &hHash))
{
CryptReleaseContext(hProv, 0);
goto Finish;
}

ppCertCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, bcert,lenCert);
if (ppCertCtx == NULL) {
goto Finish;
}

HCRYPTKEY hPubKey = 0;
CERT_PUBLIC_KEY_INFO kInf = ppCertCtx->pCertInfo->SubjectPublicKeyInfo;
if(!CryptImportPublicKeyInfo(hProv, (DWORD) ppCertCtx->dwCertEncodingType, &kInf, &hPubKey)) {
goto Finish;
}

tempSig = (BYTE*) malloc(signLen);
DWORD j;
for(j = 0; j < signLen; j++)
{
tempSig[j] = bSign[signLen - j - 1];
}

if(!CryptHashData(hHash, bData, dataLen, 0))
{
goto Finish;
}

if(CryptVerifySignature(hHash,tempSig,signLen,hPubKey,NULL, 0))
{
result = "true";
}
else
{
result = "false";
}

Finish:
if(tempSig) free(tempSig);
if(bData) free(bData);
if(bSign) free(bSign);

if(hProv) CryptReleaseContext(hProv, 0);
if(hHash) CryptDestroyHash(hHash);
if(ppCertCtx) CertFreeCertificateContext(ppCertCtx);

return result;
}

int
main(const int argc, const char **argv) {
return 1;
}

Отредактировано пользователем 31 июля 2020 г. 11:05:03(UTC)  | Причина: Не указана

Offline eisy  
#17 Оставлено : 4 августа 2020 г. 21:29:01(UTC)
eisy

Статус: Участник

Группы: Участники
Зарегистрирован: 09.07.2020(UTC)
Сообщений: 11
Российская Федерация

Сказал(а) «Спасибо»: 4 раз
Автор: Александр Лавник Перейти к цитате
Всё-таки необходимо кое-что изменить в Вашем коде:

Код:
$hd->Hash($content);

нужно заменить на:

Код:
$hd->set_DataEncoding(BASE64_TO_BINARY);
$hd->hash(base64_encode($content));


Может быть подскажете для чего это? может быть мелочь как раз в этом моменте кроется? учитывая что у меня на подпись передаются данные в ввиде "base64.base64"
Online Андрей *  
#18 Оставлено : 4 августа 2020 г. 22:29:44(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 9,435
Мужчина
Российская Федерация

Сказал «Спасибо»: 343 раз
Поблагодарили: 1355 раз в 1052 постах
Автор: eisy Перейти к цитате
Автор: Александр Лавник Перейти к цитате
Всё-таки необходимо кое-что изменить в Вашем коде:

Код:
$hd->Hash($content);

нужно заменить на:

Код:
$hd->set_DataEncoding(BASE64_TO_BINARY);
$hd->hash(base64_encode($content));


Может быть подскажете для чего это? может быть мелочь как раз в этом моменте кроется? учитывая что у меня на подпись передаются данные в ввиде "base64.base64"


Особенности работы с подписываемыми данными
base64 - служит для передачи данных внутрь функции, где они раскодируются в исходные (указание BASE64_TO_BINARY).
Техническую поддержку оказываем тут
Наша база знаний
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.