Перейти к содержимому

Контракт поставщика KMS

HsmSignerInterface — это публичный контракт, который реализует сторонний поставщик, предоставляющий NextPDF хранение ключей. Ваш поставщик хранит закрытый ключ. Движок формирует структуру Cryptographic Message Syntax (CMS).

Окно терминала
composer require nextpdf/core:^3

NextPDF отделяет сборку подписи от хранения ключей. Движок подготавливает диапазон байтов и собирает структуру CMS SignedData. Закрытый ключ он не хранит. Вместо этого он делегирует хранение ключей серверной части подписания по публичному контракту.

Вы реализуете один из трёх публичных контрактов:

  • SignerInterface. Базовый контракт. Он возвращает SignatureResult для переданных данных, добавляет метку времени и сообщает о поддержке долгосрочной проверки. Используйте этот контракт, когда логика подписания выполняется внутри процесса.
  • HsmSignerInterface. Контракт для хранения ключей. Реализация должна выполнять подписание внутри аппаратной границы. Закрытый ключ не должен покидать эту границу. Этот контракт реализует поставщик системы управления ключами.
  • DeferredSignerInterface. Расширение SignerInterface для асинхронных серверных частей. Вызывающая сторона передаёт данные, получает идентификатор задания и извлекает результат позже.

Эта страница описывает публичный контракт. Она не описывает конкретную внутреннюю реализацию NextPDF Pro или NextPDF Enterprise. Платная редакция может предоставить поддерживаемую реализацию этого контракта. Ваша интеграция зависит от контракта, а не от реализации.

Контракт требует, чтобы закрытый ключ никогда не покидал защищённую границу. Устоявшаяся практика управления ключами поддерживает это требование. National Institute of Standards and Technology (NIST) SP 800-57 Part 1 Revision 5 рассматривает управление ключами как работу с ключами на протяжении всего жизненного цикла: безопасную генерацию, хранение, распространение, использование и уничтожение. Public-Key Cryptography Standards #11 (PKCS#11) v3.1 позволяет принудительно обеспечить эту границу. Когда объект закрытого ключа устанавливает CKA_SENSITIVE в true или CKA_EXTRACTABLE в false, токен не должен раскрывать значение ключа в открытом виде за пределами токена.

За соблюдение этого требования отвечает ваша реализация. Движок не может обеспечить его за вас. Если ваш метод sign() способен прочитать необработанные байты ключа в память процесса, контракт теряет своё свойство безопасности.

NextPDF\Contracts\HsmSignerInterface (стабильный, начиная с 1.0.0):

МетодВозвращаетНазначение
sign(string $data, string $algorithm)stringПодписывает данные внутри аппаратной границы. Возвращает необработанные байты подписи. При сбое выбрасывает RuntimeException.
getCertificateDer()stringВозвращает сертификат подписанта X.509 в формате Distinguished Encoding Rules (DER).
getCertificateChainDer()array<string>Возвращает промежуточные сертификаты, от издателя к корневому, исключая сертификат подписанта.
getPublicKeyAlgorithm()stringВозвращает идентификатор алгоритма открытого ключа.

NextPDF\Contracts\SignerInterface (стабильный, начиная с 1.0.0):

МетодВозвращаетНазначение
sign(string $data)SignatureResultВозвращает CMS SignedData в DER-кодировке.
timestamp(string $signatureValue)stringВозвращает токен метки времени Request for Comments (RFC) 3161 в DER-кодировке.
supportsLtv()boolСообщает, можно ли встроить данные долгосрочной проверки (LTV).

NextPDF\Contracts\DeferredSignerInterface (экспериментальный, начиная с 3.0.0) расширяет SignerInterface методами submitForSigning(), retrieveSignature() и isComplete() для асинхронных серверных частей подписания.

Уровни подписи, которые формирует движок, соответствуют профилям PDF Advanced Electronic Signatures (PAdES). European Telecommunications Standards Institute (ETSI) EN 319 142-2 определяет расширенные профили PAdES, построенные на базовых компонентах из EN 319 142-1. Движок сопоставляет уровни B-B, B-T, B-LT и B-LTA с этими компонентами. Ваша реализация подписанта предоставляет криптографическую операцию и материал сертификата, необходимые движку.

Этот минимальный поставщик в стиле PKCS#11 делегирует подписание токену. PHP никогда не читает значение ключа.

<?php
declare(strict_types=1);
use NextPDF\Contracts\HsmSignerInterface;
final class TokenSigner implements HsmSignerInterface
{
public function __construct(private readonly TokenSession $session) {}
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
{
// The token computes the signature. The key stays inside the token.
return $this->session->c_sign($data, $algorithm);
}
public function getCertificateDer(): string
{
return $this->session->readCertificate();
}
/** @return array<string> */
public function getCertificateChainDer(): array
{
return $this->session->readChain();
}
public function getPublicKeyAlgorithm(): string
{
return 'rsaEncryption';
}
}

Поставщик для рабочей среды проверяет входные данные, при ошибке токена отказывает в обслуживании и никогда не записывает в журнал материал ключа или подписи.

<?php
declare(strict_types=1);
use NextPDF\Contracts\HsmSignerInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
final class KmsSigner implements HsmSignerInterface
{
public function __construct(
private readonly RemoteKmsClient $kms,
private readonly string $keyId,
private readonly LoggerInterface $logger,
) {}
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
{
if ($data === '') {
throw new RuntimeException('Refusing to sign empty data');
}
try {
// The KMS performs the operation. The key never reaches this process.
return $this->kms->sign($this->keyId, $data, $algorithm);
} catch (\Throwable $error) {
// Fail closed. Do not log key material or signature bytes.
$this->logger->error('kms.sign.failed', ['key' => $this->keyId]);
throw new RuntimeException('KMS signing failed', previous: $error);
}
}
public function getCertificateDer(): string
{
return $this->kms->certificate($this->keyId);
}
/** @return array<string> */
public function getCertificateChainDer(): array
{
return $this->kms->chain($this->keyId);
}
public function getPublicKeyAlgorithm(): string
{
return $this->kms->algorithm($this->keyId);
}
}
  • Формат байтов подписи. Возвращайте необработанные байты подписи. Для Rivest-Shamir-Adleman (RSA) байты представлены в формате DER. Для Elliptic Curve Digital Signature Algorithm (ECDSA) байты состоят из необработанного значения r, за которым следует значение s.
  • Порядок цепочки. getCertificateChainDer() исключает сертификат подписанта. Упорядочьте промежуточные сертификаты от издателя к корневому.
  • Идентификаторы алгоритмов. sign() использует идентификаторы в стиле OpenSSL. getPublicKeyAlgorithm() возвращает имя алгоритма X.509.
  • Отказ происходит по принципу fail-closed. При любой ошибке токена или KMS выбрасывайте RuntimeException. Не возвращайте частичную или пустую подпись.
  • Уничтожение ключа. Когда ключ достигает конца своего криптопериода, уничтожьте его в соответствии с вашей процедурой управления ключами. NIST SP 800-57 Part 1 Revision 5 §8.2.1.2 устанавливает, что ключ следует уничтожить, как только он больше не нужен. Само уничтожение выполняется согласно §8.3.4.

Местонахождение данных и меры защиты персональных данных

Заголовок раздела «Местонахождение данных и меры защиты персональных данных»

Контракт передаёт только данные для подписания и материал сертификата. Он не передаёт серверной части подписания содержимое документа или персональные данные. Делайте диапазон байтов минимальным. Не помещайте персональные данные в поля причины или местоположения подписания. Эти поля остаются видимыми в подписанном файле.

Безопасная телеметрия и очистка журналов

Заголовок раздела «Безопасная телеметрия и очистка журналов»

Никогда не записывайте в журнал данные, переданные в sign(), возвращённые байты подписи, идентификатор ключа в обратимом виде или любой закрытый компонент сертификата. Записывайте в журнал только результат операции и необратимую ссылку. Хук SignatureAppliedEvent — поддерживаемая точка привязки для аудита. См. Триггеры действий.

АктивУгрозаМера защиты
Закрытый ключУтечка в память процессаКонтракт требует подписания внутри границы; PKCS#11 CKA_SENSITIVE / CKA_EXTRACTABLE не позволяют извлечь ключ
Оракул подписанияНеограниченные запросы на подписаниеРеализация ограничивает частоту запросов и аутентифицирует вызывающие стороны
Цепочка сертификатовПодменаРеализация возвращает цепочку, ведущую к доверенному корню
Байты подписиРаскрытие через журналыПуть обработки ошибок по принципу fail-closed; никакого материала подписи в телеметрии
Ключ после истечения криптопериодаПродолжение использованияУничтожение ключа согласно NIST SP 800-57 Part 1 Revision 5 §8.2.1.2

Уровни подписи соответствуют профилям PAdES. ETSI EN 319 142-2 §5.1 определяет расширенные профили PAdES на базовых компонентах EN 319 142-1. Движок собирает эти компоненты из материала, который предоставляет ваша реализация подписанта. Управление ключами согласовано с жизненным циклом NIST SP 800-57 Part 1 Revision 5, включая требование к уничтожению из §8.2.1.2. Аппаратное хранение ключей согласовано с атрибутами неизвлекаемого ключа PKCS#11 v3.1. Ссылки на источники записаны во вводной части страницы.

Экспортный контроль и управление рецензированием

Заголовок раздела «Экспортный контроль и управление рецензированием»

Эта страница охватывает хранение ключей в PKCS#11 и в аппаратном модуле безопасности (HSM), поэтому в её вводной части задано export_control_class: legal-review-required. Согласно политике рецензирования документации (план §17, контроль 6), любая страница, где режим безопасности, путь или содержимое совпадают с PAdES, FIPS, HSM или PKCS#11, требует одобрения от команды GitHub @nextpdf-labs/crypto-reviewers перед публикацией. Это одобрение CODEOWNERS — обязательный контроль слияния: страница остаётся publish: false, пока не завершатся и юридическая проверка экспортного контроля, и рецензирование от @nextpdf-labs/crypto-reviewers.

NextPDF Enterprise предоставляет поддерживаемую реализацию этого контракта с хранением ключей в системе управления ключами, сборкой цепочки сертификатов и интеграцией с аудитом. Вы можете самостоятельно реализовать HsmSignerInterface в Core или использовать реализацию Enterprise через тот же публичный контракт без изменений кода.

В глоссарии определены система управления ключами, криптопериод и HSM; каноническое определение каждого термина см. в опубликованном глоссарии.