Pro редакция
Облачная подпись через KMS — глубокий справочник
Эта страница — справочник контрактного уровня по поверхности облачной KMS-подписи NextPDF Pro. Поверхность состоит из одного Service Provider Interface, NextPDF\Pro\Security\Signing\Kms\KmsSignerInterface, и трёх подписантов провайдеров: AwsKmsSigner, AzureKeyVaultSigner и GcpKmsSigner. Два адаптера, AwsKmsSigningStrategy и AzureKeyVaultSigningStrategy, связывают подписанта с контрактом Pro SigningStrategy. Каждый подписант отправляет своему провайдеру только дайджест сообщения по HTTP через PSR-18. Приватный ключ и документ не пересекают границу. Эта страница описывает публичный API, контракт наблюдаемого поведения и типизированные режимы отказа. Оркестрация сессий (RemoteSigningSession, SequentialSigner) и метки времени (PadesBtTimestamper) описаны на собственных страницах.
Доступность и лицензирование
Заголовок раздела «Доступность и лицензирование»Эта возможность поставляется в составе NextPDF Pro (nextpdf/pro) и активируется лицензионным конвертом уровня Pro. Развёртывание без этого права не загружает классы данной возможности. Сравните редакции и получите лицензию.
Поверхность публичного API
Заголовок раздела «Поверхность публичного API»| Символ | Параметры | Поведение по умолчанию | Возвращает | Бросает или отказывает с | Примечания |
|---|---|---|---|---|---|
KmsSignerInterface | — | Расширяет контракт Core HsmSignerInterface | — | — | SPI для драйверов KMS и HSM; зарезервированные встроенные идентификаторы: aws-kms, azure-keyvault, gcp-kms, pkcs11, openssl-cli |
KmsSignerInterface::providerId() | нет | Стабильный ключ поиска в реестре | non-empty-string | — | Сторонние драйверы должны выделять свой идентификатор в пространство имён |
KmsSignerInterface::signWithVersion() | $data, $algorithm = 'sha256WithRSAEncryption', $keyVersion = null | null-версия ключа откатывается к умолчанию провайдера | string октеты подписи: RSA как возвращено провайдером (помещаются напрямую в SignerInfo.signature), ECDSA как DER ECDSA-Sig-Value по правилам CMS | KeyManagementException, UnsupportedAlgorithmException, SignatureFailedException | Семантика null различается у провайдеров; см. контракт поведения |
KmsSignerInterface::supportsAlgorithm() | string $algorithm | Проба возможностей; ввода-вывода не выполняет | bool | — | Вызывается перед выбором провайдера |
KmsSignerInterface::supportedAlgorithms() | нет | Перечисляет имена в стиле OpenSSL, принимаемые провайдером | list<non-empty-string> | — | — |
AwsKmsSigner | конструктор: AwsKmsConfig, DER сертификата, DER цепочки, клиент PSR-18, фабрики PSR-17, логгер PSR-3 | Алгоритм по умолчанию KmsSigningAlgorithm::RsaPkcs1Sha256 | — | см. методы | final; PROVIDER_ID = 'aws-kms' |
AwsKmsSigner::create() | id ключа, DER сертификата, зависимости PSR, опциональная цепочка, конфиг, логгер | Строит AwsKmsConfig::fromEnvironment($keyId), когда $config равно null | self | — | Читает стандартные переменные окружения AWS_* |
AwsKmsSigner::withAlgorithm() | KmsSigningAlgorithm $algorithm | Возвращает изменённый клон | self | — | Должен соответствовать типу ключа, подготовленного в AWS KMS |
AwsKmsSigner::sign() | $data, $algorithm = 'sha256WithRSAEncryption' | Делегирует в signWithVersion($data, $algorithm, null) | string | как signWithVersion() | Путь устаревшего двухаргументного контракта Core |
AzureKeyVaultSigner | конструктор: AzureKeyVaultConfig, DER сертификата, DER цепочки, клиент PSR-18, фабрики PSR-17, логгер PSR-3 | Алгоритм по умолчанию AzureSigningAlgorithm::Rs256; access-токен из конфига задаёт bearer-токен | — | см. методы | final; PROVIDER_ID = 'azure-keyvault' |
AzureKeyVaultSigner::create() | имя хранилища, имя ключа, DER сертификата, зависимости PSR, опциональная цепочка, конфиг, логгер | Строит AzureKeyVaultConfig::fromEnvironment(), когда $config равно null | self | — | Поддерживает заранее полученный токен или учётные данные service principal |
AzureKeyVaultSigner::withAlgorithm() | AzureSigningAlgorithm $algorithm | Возвращает изменённый клон | self | — | Ключи RSA используют значения RS/PS; ключи EC — значения ES |
GcpKmsSigner | конструктор: GcpKmsConfig, DER сертификата, DER цепочки, клиент PSR-18, фабрики PSR-17, логгер PSR-3 | Алгоритм по умолчанию GcpKmsSigningAlgorithm::RsaSignPkcs1_2048Sha256 | — | см. методы | final; PROVIDER_ID = 'gcp-kms', API_VERSION = 'v1' |
GcpKmsSigner::create() | id проекта, локация, кольцо ключей, крипто-ключ, DER сертификата, зависимости PSR, опциональная цепочка, конфиг, логгер | Строит GcpKmsConfig::fromEnvironment(), когда $config равно null | self | — | Получение bearer-токена делегируется вызывающей стороне |
GcpKmsSigner::withAlgorithm() | GcpKmsSigningAlgorithm $algorithm | Только предпросмотр на этапе конфигурации; на этапе подписи побеждает имя wire каждого вызова | self | — | Размер ключа зафиксирован подготовленной CryptoKeyVersion |
AwsKmsSigningStrategy | конструктор: AwsKmsSigner $signer | Синхронный; isAsync() возвращает false | — | Пробрасывает исключения обёрнутого подписанта | Адаптер для RemoteSigningSession::complete() |
AzureKeyVaultSigningStrategy | конструктор: AzureKeyVaultSigner $signer | Синхронный; isAsync() возвращает false | — | Пробрасывает исключения обёрнутого подписанта | Адаптер для RemoteSigningSession::complete() |
KmsSigningAlgorithm | enum, 9 вариантов (RSA PKCS#1, RSA-PSS, ECDSA; SHA-256/384/512) | — | Значения wire SigningAlgorithm AWS KMS | InvalidArgumentException из fromOpenSslName() | resolveForWireName() сохраняет настроенный дайджест PSS |
AzureSigningAlgorithm | enum, 9 вариантов (RS256…ES512) | — | Значения в стиле JWA Azure Key Vault | InvalidArgumentException из fromOpenSslName() | isEcdsa() помечает значения, вывод которых требует конверсии в DER |
GcpKmsSigningAlgorithm | enum, 10 вариантов (EC P-256/P-384, RSA PKCS#1, RSA-PSS) | — | Значения алгоритма CryptoKeyVersion GCP | UnsupportedAlgorithmException из fromOpenSslName() | Разрешение имени wire выбирает наименьший подходящий размер ключа |
Сигнатуры точек входа
Заголовок раздела «Сигнатуры точек входа»public function providerId(): string;
public function signWithVersion( string $data, string $algorithm = 'sha256WithRSAEncryption', ?string $keyVersion = null,): string;
public function supportsAlgorithm(string $algorithm): bool;
public function supportedAlgorithms(): array;public static function create( string $keyId, string $certDer, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, array $chainDer = [], ?AwsKmsConfig $config = null, ?LoggerInterface $logger = null,): self
public function withAlgorithm(KmsSigningAlgorithm $algorithm): self
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): stringpublic static function create( string $vaultName, string $keyName, string $certDer, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, array $chainDer = [], ?AzureKeyVaultConfig $config = null, ?LoggerInterface $logger = null,): self
public function withAlgorithm(AzureSigningAlgorithm $algorithm): selfpublic static function create( string $projectId, string $location, string $keyRing, string $cryptoKey, string $certDer, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, array $chainDer = [], ?GcpKmsConfig $config = null, ?LoggerInterface $logger = null,): self
public function withAlgorithm(GcpKmsSigningAlgorithm $algorithm): selfpublic function __construct( private AwsKmsSigner $signer,) {}
public function sign(string $signedAttributesDer): stringpublic function __construct( private AzureKeyVaultSigner $signer,) {}
public function sign(string $signedAttributesDer): stringКонтракт поведения
Заголовок раздела «Контракт поведения»Разрешение контракта
Заголовок раздела «Разрешение контракта»KmsSignerInterface расширяет контракт Core HsmSignerInterface. Он добавляет providerId(), учитывающий версию ключа signWithVersion(), а также пробы возможностей supportsAlgorithm() и supportedAlgorithms(). Унаследованный двухаргументный sign() делегирует в signWithVersion() с null-версией ключа во всех трёх подписантах. getCertificateDer(), getCertificateChainDer() и getPublicKeyAlgorithm() реализованы на основе материала, переданного в конструктор. Пробы возможностей не выполняют ввода-вывода. Каждый подписант также предоставляет аксессоры getSigningAlgorithm() и getConfig() для инспекции.
Передача только дайджеста
Заголовок раздела «Передача только дайджеста»Каждый подписант хеширует $data локально дайджестом разрешённого алгоритма и передаёт только этот дайджест. AWS получает base64-дайджест с MessageType: DIGEST. Azure получает base64url-дайджест в теле запроса подписи. GCP получает base64-дайджест в поле дайджеста, специфичном для алгоритма. Байты документа никогда не появляются в запросе к провайдеру. Весь транспорт использует стандартный HTTP-клиент PSR-18 поверх HTTPS-эндпоинта провайдера; никакой облачный вендорский SDK не задействован.
Разрешение версии ключа
Заголовок раздела «Разрешение версии ключа»signWithVersion() проверяет аргумент версии ключа по принципу fail-closed до построения любого запроса. Значение, не проходящее грамматику провайдера, поднимает KeyManagementException и предотвращает инъекцию сегмента URL или KeyId.
| Провайдер | null-версия ключа | Пустая строка | Грамматика переопределения |
|---|---|---|---|
AwsKmsSigner | Использует AwsKmsConfig::$keyId; алиас или ARN разрешается в текущий ключ на стороне провайдера | Отклоняется | UUID (с дефисами или без), alias/<name> или ARN ключа/алиаса KMS |
AzureKeyVaultSigner | Использует настроенную версию ключа; пустое значение в конфиге выбирает последнюю включённую версию на стороне сервера | Отклоняется | 32-символьный шестнадцатеричный идентификатор |
GcpKmsSigner | Использует версию, привязанную в GcpKmsConfig; если не привязана — поднимает KeyManagementException | Отклоняется | Десятичный id CryptoKeyVersion, только цифры |
У GCP нет серверного примитива «активной версии». Эндпоинт асимметричной подписи работает только над конкретным ресурсом cryptoKeyVersions/{n}, поэтому версия всегда должна быть разрешимой.
Разрешение алгоритма
Заголовок раздела «Разрешение алгоритма»Слой стратегии передаёт имя wire в стиле OpenSSL. AWS и Azure принимают семь имён wire (PKCS#1 и ECDSA при SHA-256/384/512, плюс RSASSA-PSS). GCP принимает пять (sha256WithRSAEncryption, sha512WithRSAEncryption, RSASSA-PSS, ecdsa-with-SHA256, ecdsa-with-SHA384). Имя wire RSASSA-PSS не кодирует дайджест, поэтому оно неоднозначно по дайджесту. AwsKmsSigner разрешает его через KmsSigningAlgorithm::resolveForWireName(), который сохраняет дайджест настроенного варианта PSS. AzureKeyVaultSigner доверяет настроенному варианту PSS для неоднозначного имени. Он поднимает UnsupportedAlgorithmException, если разрешённый дайджест PSS расходится с настроенным. GcpKmsSigner заново разрешает enum из имени wire на каждом вызове; withAlgorithm() на GCP — это предпросмотр на этапе конфигурации и не меняет поведение на этапе подписи. Неподдерживаемое имя wire поднимает UnsupportedAlgorithmException до любого сетевого вызова. На AwsKmsSigner и GcpKmsSigner вызов подписи обновляет значение, впоследствии сообщаемое getSigningAlgorithm(), до разрешённого на этот вызов алгоритма. На AzureKeyVaultSigner разрешение локально для вызова, и настроенное значение остаётся авторитетным.
Нормализация подписи
Заголовок раздела «Нормализация подписи»AWS и GCP возвращают подписи в форме, которую потребляет CMS: октеты подписи RSA попадают в SignerInfo.signature без изменений, а ECDSA приходит в DER-кодировке. Azure возвращает ECDSA в сыром виде IEEE P1363 (r||s), который подписант конвертирует в DER ECDSA-Sig-Value перед возвратом.
Интеграция с CMS и смежность
Заголовок раздела «Интеграция с CMS и смежность»Адаптер SigningStrategy подписывает DER-кодированные подписанные атрибуты, предоставленные сессией. При наличии подписанных атрибутов вход подписи CMS — это дайджест полной DER-кодировки значения SignedAttrs — RFC 5652 §5.4. Методы адаптера getSignatureAlgorithmOid() и getDigestAlgorithm() питают поля SignerInfo signatureAlgorithm и digestAlgorithm — RFC 5652 §5.3. Возвращённые байты становятся OCTET STRING подписи SignerInfo — RFC 5652 §5.5. Сборка CMS, обработка ByteRange и жизненный цикл сессии принадлежат RemoteSigningSession; многосторонние потоки принадлежат SequentialSigner. Метка времени подписи PAdES B-T, чей messageImprint хеширует значение подписи SignerInfo — RFC 3161 Appendix A — применяется PadesBtTimestamper, а не этими подписантами. Все три описаны в глубоком справочнике безопасности Pro.
Граничные случаи и режимы отказа
Заголовок раздела «Граничные случаи и режимы отказа»- Версия ключа в виде пустой строки отклоняется у всех трёх провайдеров. Передайте
null, чтобы унаследовать настроенное умолчание. - Некорректная версия ключа отклоняется до построения любого запроса, а нарушающее значение указывается в исключении.
AwsKmsSignerс пустымAwsKmsConfig::$keyIdиnull-версией ключа поднимаетKeyManagementException.- Ответы провайдера, указывающие на сбой управления ключами, отображаются в
KeyManagementException: AWSNotFoundException,DisabledException,KeyUnavailableException,InvalidKeyUsageExceptionили HTTP 404; Azure HTTP 404,KeyNotFound,KeyDisabledилиKeyNotActive; GCP HTTP 404 или 409,NOT_FOUND,FAILED_PRECONDITIONлибо HTTP 400, сообщение которого называет версию. - Прочие ответы провайдера, отличные от 200, поднимают
SignatureFailedExceptionна AWS и GCP иAzureKeyVaultExceptionна Azure. - Сбой транспорта PSR-18 во время подписи отображается в
SignatureFailedExceptionс сохранением клиентского исключения как предыдущего throwable. AzureKeyVaultSignerбез access-токена и без учётных данных service principal поднимаетAzureKeyVaultExceptionдо любого обращения к хранилищу. Неудачное получение токена Azure AD также поднимаетAzureKeyVaultException.AzureKeyVaultSignerпроверяет имя хранилища, имя ключа, версию ключа и tenant id по опубликованным грамматикам Azure в узловой точке запроса. Значение, несущее URL-структурные символы, отказывает по принципу fail-closed сAzureKeyVaultException.GcpKmsSignerбез OAuth2 bearer-токена поднимаетSignatureFailedException; получение токена — ответственность вызывающей стороны.- Ответ провайдера, не являющийся валидным JSON или не содержащий поля подписи, поднимает
SignatureFailedException(Azure: отсутствие поляvalueподнимаетAzureKeyVaultException). - Поле подписи провайдера, не проходящее base64-декодирование, поднимает
SignatureFailedExceptionна AWS и GCP иAzureKeyVaultExceptionна Azure. - В версии 3.1.0 не поставляется адаптер
SigningStrategyдляGcpKmsSigner. Подписант GCP потребляется напрямую через контрактKmsSignerInterface.
Поведение в режиме FIPS
Заголовок раздела «Поведение в режиме FIPS»AwsKmsConfig::withFipsEndpoint() направляет запросы на эндпоинт kms-fips региона. Статус FIPS-валидации этого эндпоинта — свойство AWS, а не NextPDF. AzureKeyVaultConfig и GcpKmsConfig не предоставляют выделенного помощника для FIPS-эндпоинта в 3.1.0. Вычисление дайджеста выполняется в процессе функцией PHP hash() и само по себе не является валидированным модулем. NextPDF Pro может работать против границы KMS или HSM, прошедшей FIPS-валидацию, но NextPDF не является FIPS-валидированным криптографическим модулем и не заявляет FIPS-сертификации.
Соответствие
Заголовок раздела «Соответствие»| Заявление | Стандарт | Пункт |
|---|---|---|
| Стратегия подписывает DER-кодированные подписанные атрибуты; дайджест входа подписи CMS покрывает полную DER-кодировку SignedAttrs. | RFC 5652 | §5.4 |
| SignedAttributes DER-кодированы и несут как минимум content-type и message-digest; signatureAlgorithm идентифицирует алгоритм подписанта. | RFC 5652 | §5.3 |
| Возвращённые байты подписи закодированы как OCTET STRING и помещены в поле подписи SignerInfo. | RFC 5652 | §5.5 |
messageImprint метки времени подписи хеширует значение подписи SignerInfo (смежная поверхность B-T, не эти подписанты). | RFC 3161 | Appendix A |
Все пункты переданы своими словами; NextPDF не воспроизводит нормативный текст. Это заявления о возможностях, а не сертификации. NextPDF не держит сертификации и не предоставляет её. Верифицируется ли произведённая подпись — решение верификатора относительно его собственных якорей доверия и политики; подписанты возвращают байты подписи и не утверждают доверенного исхода. Хранение ключа, защита ключа и проверка алгоритма на стороне провайдера — свойства настроенного KMS, а не NextPDF.
Заметки по разработке
Заголовок раздела «Заметки по разработке»- Доступность внутри пакета Pro:
AwsKmsSignerс 1.9.0,AzureKeyVaultSignerс 2.0.0,GcpKmsSignerиKmsSignerInterfaceс 2.1.0. Все актуальны вnextpdf/pro3.1.0. - Подписанты зависят только от PSR-18, PSR-17 и PSR-3. Никакой SDK AWS, Azure или Google не требуется и не поставляется.
- Пробуйте
supportsAlgorithm()до подписи, чтобы несовместимый провайдер отклонялся на этапе выбора, а не в середине сессии. - Поля учётных данных внедряются через конструктор и помечены как чувствительные параметры. Сообщения лога несут только структурные поля; ни учётные данные, ни токен, ни содержимое документа в логи не записываются.
- Привязывайте версии ключа явно в регулируемых развёртываниях. Умолчания разрешения алиаса (AWS) и последней включённой версии (Azure) удобны, но не детерминированы при ротациях.
- Сторонние драйверы реализуют
KmsSignerInterfaceи должны выделять свойproviderId()в пространство имён во избежание коллизий с зарезервированными встроенными идентификаторами.
См. также
Заголовок раздела «См. также»- Облачная подпись через KMS (возможность) — практическая страница: настройка, конфигурация и граница хранения ключа.
- Безопасность — глубокий справочник —
RemoteSigningSession,SequentialSigner, поверхность PAdES B-B/B-T и контрактSigningStrategy. - Подпись — глубокий справочник (Enterprise) — граница долгосрочного производителя B-LT/B-LTA.
- Безопасность / Подпись (Core) — CMS-подписант Core и контракты, которые расширяет эта поверхность.
Граница публикации
Заголовок раздела «Граница публикации»Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую поверхность публичного API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов runbook и префиксы тикетов вне области рассмотрения.