Проверка подписей

This commit is contained in:
Artem Vasilev 2022-11-08 20:44:01 +03:00
parent 18a156a586
commit e077c60c2b
2 changed files with 198 additions and 4 deletions

View File

@ -0,0 +1,17 @@
<?php
namespace Webmasterskaya\CryptoPro\Constants;
/**
* Тип перечисления CAPICOM_ENCODING_TYPE указывает используемый тип кодирования.
*
* @link https://learn.microsoft.com/windows/win32/seccrypto/capicom-encoding-type?redirectedfrom=MSDN
*/
class CAPICOM_ENCODE
{
const ANY = 0xffffffff; // Данные сохраняются в виде строки в кодировке Base64 или чистой двоичной последовательности. Этот тип кодирования используется только для входных данных с неизвестным типом кодирования. Представлен в CAPICOM 2.0.
const BASE64 = 0; // Данные сохраняются в виде строки в кодировке Base64.
const BINARY = 1; // Данные сохраняются в виде чистой двоичной последовательности.
}

View File

@ -3,6 +3,7 @@
namespace Webmasterskaya\CryptoPro; namespace Webmasterskaya\CryptoPro;
use Webmasterskaya\CryptoPro\Constants\CAPICOM_CERTIFICATE_FIND_TYPE; use Webmasterskaya\CryptoPro\Constants\CAPICOM_CERTIFICATE_FIND_TYPE;
use Webmasterskaya\CryptoPro\Constants\CAPICOM_ENCODE;
use Webmasterskaya\CryptoPro\Constants\CAPICOM_PROPID; use Webmasterskaya\CryptoPro\Constants\CAPICOM_PROPID;
use Webmasterskaya\CryptoPro\Helpers\CertificateHelper; use Webmasterskaya\CryptoPro\Helpers\CertificateHelper;
use Webmasterskaya\CryptoPro\Helpers\ErrorMessageHelper; use Webmasterskaya\CryptoPro\Helpers\ErrorMessageHelper;
@ -258,7 +259,6 @@ class CryptoPro
$cadesSigner->set_Certificate($cadesCertificate); $cadesSigner->set_Certificate($cadesCertificate);
/** @var \CPAttributes $cadesAuthAttrs */
$cadesAuthAttrs = $cadesSigner->get_AuthenticatedAttributes(); $cadesAuthAttrs = $cadesSigner->get_AuthenticatedAttributes();
$cadesAuthAttrs->Add($cadesAttrs); $cadesAuthAttrs->Add($cadesAttrs);
@ -266,7 +266,6 @@ class CryptoPro
$cadesSignedData->set_Content($messageBase64); $cadesSignedData->set_Content($messageBase64);
$cadesSigner->set_Options(CERTIFICATE_INCLUDE_WHOLE_CHAIN); $cadesSigner->set_Options(CERTIFICATE_INCLUDE_WHOLE_CHAIN);
} }
catch (\Throwable $e) catch (\Throwable $e)
{ {
@ -280,7 +279,7 @@ class CryptoPro
$cadesSigner, $cadesSigner,
PKCS7_TYPE, PKCS7_TYPE,
false, false,
ENCODE_BASE64 CAPICOM_ENCODE::BASE64
); );
} }
catch (\Throwable $e) catch (\Throwable $e)
@ -367,7 +366,13 @@ class CryptoPro
try try
{ {
$signature = $cadesSignedData->SignHash($cadesHashedData, $cadesSigner, PKCS7_TYPE); /** @var string $signature */
$signature = $cadesSignedData->SignHash(
$cadesHashedData,
$cadesSigner,
PKCS7_TYPE,
CAPICOM_ENCODE::BASE64
);
} }
catch (\Throwable $e) catch (\Throwable $e)
{ {
@ -844,4 +849,176 @@ class CryptoPro
return $cadesCertificate; return $cadesCertificate;
} }
/**
* Проверяет присоеденённую подпись и возвращает информацию о подписантах
*
* @param string $signedMessage подписанное сообщение
*
* @throws \Exception
* @return array Информация о подписантах
*/
public static function verifyAttachedSignature(string $signedMessage)
{
try
{
$cadesSignedData = new \CPSignedData();
$cadesSignedData->set_Content($signedMessage);
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка при инициализации проверки подписи'));
}
try
{
$cadesSignedData->VerifyCades($signedMessage, CADES_BES, false);
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка при проверке подписи'));
}
try
{
$cadesSigners = $cadesSignedData->get_Signers();
$cadesSignersCount = (int) $cadesSigners->get_Count();
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка получения списка подписантов'));
}
if (!$cadesSignersCount)
{
throw new \Exception('Нет доступных подписантов');
}
$signers = [];
try
{
while ($cadesSignersCount)
{
$cadesSigner = $cadesSigners->get_Item($cadesSignersCount);
$cadesCertificate = $cadesSigner->get_Certificate();
$certificate = new Certificate(
$cadesCertificate,
CertificateHelper::extractCommonName($cadesCertificate->get_SubjectName()),
$cadesCertificate->get_IssuerName(),
$cadesCertificate->get_SubjectName(),
$cadesCertificate->get_Thumbprint(),
$cadesCertificate->get_ValidFromDate(),
$cadesCertificate->get_ValidToDate()
);
$signers[] = [
'signing_time' => $cadesSigner->get_SigningTime(),
'certificate' => $certificate
];
$cadesSignersCount--;
}
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка при чтении информации о подписанте'));
}
return $signers;
}
/**
* Проверяет отсоеденённую подпись по значению хэш-функции и возвращает информацию о подписантах
*
* @param string $signedMessage подписанное сообщение
* @param string $messageHash хеш подписываемого сообщения, сгенерированный по ГОСТ Р 34.11-2012 256 бит
*
* @throws \Exception
* @return array Информация о подписантах
*/
public static function verifyDetachedSignature(string $signedMessage, string $messageHash)
{
try
{
$cadesSignedData = new \CPSignedData();
$cadesHashedData = new \CPHashedData();
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка при инициализации проверки подписи'));
}
try
{
$cadesHashedData->set_Algorithm(CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256);
$cadesHashedData->SetHashValue($messageHash);
// Для получения объекта отсоединенной (открепленной) подписи, необходимо задать любой контент.
// Этот баг описан на форуме.
// https://www.cryptopro.ru/forum2/default.aspx?g=posts&m=78553#post78553
$cadesSignedData->set_Content(123);
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка при установке хеша'));
}
try
{
$cadesSignedData->VerifyHash($cadesHashedData, $signedMessage, PKCS7_TYPE);
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка при проверке подписи'));
}
try
{
$cadesSigners = $cadesSignedData->get_Signers();
$cadesSignersCount = (int) $cadesSigners->get_Count();
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка получения списка подписантов'));
}
if (!$cadesSignersCount)
{
throw new \Exception('Нет доступных подписантов');
}
$signers = [];
try
{
while ($cadesSignersCount)
{
$cadesSigner = $cadesSigners->get_Item($cadesSignersCount);
$cadesCertificate = $cadesSigner->get_Certificate();
$certificate = new Certificate(
$cadesCertificate,
CertificateHelper::extractCommonName($cadesCertificate->get_SubjectName()),
$cadesCertificate->get_IssuerName(),
$cadesCertificate->get_SubjectName(),
$cadesCertificate->get_Thumbprint(),
$cadesCertificate->get_ValidFromDate(),
$cadesCertificate->get_ValidToDate()
);
$signers[] = [
'signing_time' => $cadesSigner->get_SigningTime(),
'certificate' => $certificate
];
$cadesSignersCount--;
}
}
catch (\Throwable $e)
{
throw new \Exception(ErrorMessageHelper::getErrorMessage($e, 'Ошибка при чтении информации о подписанте'));
}
return $signers;
}
} }