Files
alfa-bank-sdk/src/Services/OpenSslCmsSigner.php
2026-03-10 22:29:35 +03:00

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.");
}
}