70 lines
2.4 KiB
PHP
70 lines
2.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Apoloz\AlfaBank\Services;
|
|
|
|
use Apoloz\AlfaBank\Contracts\SignerInterface;
|
|
use Apoloz\AlfaBank\Exceptions\SignerException;
|
|
|
|
class OpenSslCmsSigner implements SignerInterface
|
|
{
|
|
public function __construct(
|
|
protected string $certificatePath,
|
|
protected string $privateKeyPath
|
|
) {}
|
|
|
|
public function sign(string $data): string
|
|
{
|
|
if (!file_exists($this->privateKeyPath)) {
|
|
throw new SignerException("Private key file not found: {$this->privateKeyPath}");
|
|
}
|
|
if (!file_exists($this->certificatePath)) {
|
|
throw new SignerException("Certificate file not found: {$this->certificatePath}");
|
|
}
|
|
|
|
$privateKey = openssl_pkey_get_private(file_get_contents($this->privateKeyPath));
|
|
$cert = openssl_x509_read(file_get_contents($this->certificatePath));
|
|
|
|
if (!$privateKey || !$cert) {
|
|
throw new SignerException("Could not read private key or certificate for signing.");
|
|
}
|
|
|
|
$inFile = tempnam(sys_get_temp_dir(), 'alfa_in');
|
|
$outFile = tempnam(sys_get_temp_dir(), 'alfa_out');
|
|
|
|
file_put_contents($inFile, $data);
|
|
|
|
// Используем PKCS7_DETACHED согласно документации Альфа-Банка для digestSignatures
|
|
$status = openssl_pkcs7_sign(
|
|
$inFile,
|
|
$outFile,
|
|
$cert,
|
|
$privateKey,
|
|
[],
|
|
PKCS7_BINARY | PKCS7_DETACHED
|
|
);
|
|
|
|
if (!$status) {
|
|
@unlink($inFile);
|
|
@unlink($outFile);
|
|
throw new SignerException("OpenSSL sign failed: " . openssl_error_string());
|
|
}
|
|
|
|
$signedData = file_get_contents($outFile);
|
|
@unlink($inFile);
|
|
@unlink($outFile);
|
|
|
|
// Извлекаем Base64 тело подписи согласно примеру из документации Альфы
|
|
$parts = explode("\n\n", $signedData, 2);
|
|
if (isset($parts[1])) {
|
|
$signature = trim($parts[1]);
|
|
// Удаляем возможные PEM-завершители и переносы строк
|
|
$signature = str_replace(["-----BEGIN PKCS7-----", "-----END PKCS7-----", "\n", "\r", " "], '', $signature);
|
|
return $signature;
|
|
}
|
|
|
|
throw new SignerException("Failed to extract signature body from CMS container.");
|
|
}
|
|
}
|