Pro 版本
云 KMS 签名 — 深度参考
本页是 NextPDF Pro 云 KMS 签名面的契约级参考。该面由一个服务提供者接口 NextPDF\Pro\Security\Signing\Kms\KmsSignerInterface 和三个提供商签名器组成:AwsKmsSigner、AzureKeyVaultSigner 与 GcpKmsSigner。两个适配器 AwsKmsSigningStrategy 与 AzureKeyVaultSigningStrategy 将签名器桥接到 Pro 的 SigningStrategy 契约。每个签名器只把一个消息摘要通过 PSR-18 HTTP 发送给其提供商。私钥与文档从不跨越该边界。本页阐述公共 API、可观测的行为契约,以及有类型的失败模式。会话编排(RemoteSigningSession、SequentialSigner)与时间戳(PadesBtTimestamper)在各自的页面中说明。
可用性与许可
标题为“可用性与许可”的章节此能力随 NextPDF Pro(nextpdf/pro)交付,并以 Pro 级许可证信封激活。缺少该授权的部署不会加载此能力的类。比较版本并获取许可证。
公共 API 面
标题为“公共 API 面”的章节| 符号 | 参数 | 默认行为 | 返回 | 抛出或失败于 | 备注 |
|---|---|---|---|---|---|
KmsSignerInterface | — | 扩展 Core 的 HsmSignerInterface 契约 | — | — | KMS 与 HSM 驱动的 SPI;保留的内置 id: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 为符合 CMS 规则的 DER ECDSA-Sig-Value | KeyManagementException、UnsupportedAlgorithmException、SignatureFailedException | 各提供商的 null 语义不同;参见行为契约 |
KmsSignerInterface::supportsAlgorithm() | string $algorithm | 能力探测;不执行任何 I/O | bool | — | 在提供商选择之前调用 |
KmsSignerInterface::supportedAlgorithms() | 无 | 列出提供商接受的 OpenSSL 风格名称 | list<non-empty-string> | — | — |
AwsKmsSigner | 构造函数:AwsKmsConfig、cert DER、chain DER、PSR-18 客户端、PSR-17 工厂、PSR-3 日志器 | 算法默认为 KmsSigningAlgorithm::RsaPkcs1Sha256 | — | 参见各方法 | final;PROVIDER_ID = 'aws-kms' |
AwsKmsSigner::create() | key id、cert DER、PSR 依赖项、可选 chain、config、logger | 当 $config 为 null 时构建 AwsKmsConfig::fromEnvironment($keyId) | self | — | 读取标准的 AWS_* 环境变量 |
AwsKmsSigner::withAlgorithm() | KmsSigningAlgorithm $algorithm | 返回一个修改后的克隆 | self | — | 必须与 AWS KMS 中预置的密钥类型匹配 |
AwsKmsSigner::sign() | $data、$algorithm = 'sha256WithRSAEncryption' | 委托给 signWithVersion($data, $algorithm, null) | string | 同 signWithVersion() | 遗留的双参数 Core 契约路径 |
AzureKeyVaultSigner | 构造函数:AzureKeyVaultConfig、cert DER、chain DER、PSR-18 客户端、PSR-17 工厂、PSR-3 日志器 | 算法默认为 AzureSigningAlgorithm::Rs256;config 中的访问令牌为 bearer 令牌提供初始值 | — | 参见各方法 | final;PROVIDER_ID = 'azure-keyvault' |
AzureKeyVaultSigner::create() | vault 名称、key 名称、cert DER、PSR 依赖项、可选 chain、config、logger | 当 $config 为 null 时构建 AzureKeyVaultConfig::fromEnvironment() | self | — | 支持预先获取的令牌或服务主体凭据 |
AzureKeyVaultSigner::withAlgorithm() | AzureSigningAlgorithm $algorithm | 返回一个修改后的克隆 | self | — | RSA 密钥使用 RS/PS 值;EC 密钥使用 ES 值 |
GcpKmsSigner | 构造函数:GcpKmsConfig、cert DER、chain DER、PSR-18 客户端、PSR-17 工厂、PSR-3 日志器 | 算法默认为 GcpKmsSigningAlgorithm::RsaSignPkcs1_2048Sha256 | — | 参见各方法 | final;PROVIDER_ID = 'gcp-kms'、API_VERSION = 'v1' |
GcpKmsSigner::create() | project id、location、key ring、crypto key、cert DER、PSR 依赖项、可选 chain、config、logger | 当 $config 为 null 时构建 GcpKmsConfig::fromEnvironment() | self | — | Bearer 令牌的获取委托给调用方 |
GcpKmsSigner::withAlgorithm() | GcpKmsSigningAlgorithm $algorithm | 仅为配置期预览;签名时以每次调用的线路名称为准 | self | — | 密钥长度由预置的 CryptoKeyVersion 固定 |
AwsKmsSigningStrategy | 构造函数:AwsKmsSigner $signer | 同步;isAsync() 返回 false | — | 透传所封装签名器的异常 | 用于 RemoteSigningSession::complete() 的适配器 |
AzureKeyVaultSigningStrategy | 构造函数:AzureKeyVaultSigner $signer | 同步;isAsync() 返回 false | — | 透传所封装签名器的异常 | 用于 RemoteSigningSession::complete() 的适配器 |
KmsSigningAlgorithm | 枚举,9 个成员(RSA PKCS#1、RSA-PSS、ECDSA;SHA-256/384/512) | — | AWS KMS SigningAlgorithm 线路值 | 来自 fromOpenSslName() 的 InvalidArgumentException | resolveForWireName() 保留所配置的 PSS 摘要 |
AzureSigningAlgorithm | 枚举,9 个成员(RS256…ES512) | — | Azure Key Vault JWA 风格值 | 来自 fromOpenSslName() 的 InvalidArgumentException | isEcdsa() 标记其输出需要 DER 转换的值 |
GcpKmsSigningAlgorithm | 枚举,10 个成员(EC P-256/P-384、RSA PKCS#1、RSA-PSS) | — | GCP CryptoKeyVersion 算法值 | 来自 fromOpenSslName() 的 UnsupportedAlgorithmException | 线路名称解析选取最小的匹配密钥长度 |
入口点签名
标题为“入口点签名”的章节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() 在三个签名器上都以 null 密钥版本委托给 signWithVersion()。getCertificateDer()、getCertificateChainDer() 与 getPublicKeyAlgorithm() 依据构造函数提供的材料实现。能力探测不执行任何 I/O。每个签名器还暴露 getSigningAlgorithm() 与 getConfig() 访问器以供检视。
仅传输摘要
标题为“仅传输摘要”的章节每个签名器都在本地用所解析算法的摘要对 $data 进行哈希,并仅传输该摘要。AWS 接收带 MessageType: DIGEST 的 base64 摘要。Azure 在 sign 请求体中接收 base64url 摘要。GCP 在算法特定的摘要字段中接收 base64 摘要。文档字节从不出现在任何提供商请求中。所有传输都使用标准的 PSR-18 HTTP 客户端经由提供商的 HTTPS 端点进行;不涉及任何云厂商 SDK。
密钥版本解析
标题为“密钥版本解析”的章节signWithVersion() 在构建任何请求之前以 fail-closed 方式校验密钥版本参数。未通过提供商语法的值会引发 KeyManagementException,并阻止 URL 段或 KeyId 注入。
| 提供商 | null 密钥版本 | 空字符串 | 覆盖语法 |
|---|---|---|---|
AwsKmsSigner | 使用 AwsKmsConfig::$keyId;别名或 ARN 会在提供商侧解析为当前密钥 | 拒绝 | UUID(带或不带连字符)、alias/<name>,或一个 KMS 密钥/别名 ARN |
AzureKeyVaultSigner | 使用所配置的密钥版本;空的 config 值会在服务器端选取最新的已启用版本 | 拒绝 | 32 字符的十六进制标识符 |
GcpKmsSigner | 使用固定在 GcpKmsConfig 中的版本;若未固定任何版本,则引发 KeyManagementException | 拒绝 | 十进制 CryptoKeyVersion id,仅限数字 |
GCP 没有服务器端的“活动版本”原语。asymmetric-sign 端点只对特定的 cryptoKeyVersions/{n} 资源进行操作,因此版本必须始终可解析。
算法解析
标题为“算法解析”的章节策略层转发一个 OpenSSL 风格的线路名称。AWS 与 Azure 接受七个线路名称(SHA-256/384/512 下的 PKCS#1 与 ECDSA,外加 RSASSA-PSS)。GCP 接受五个(sha256WithRSAEncryption、sha512WithRSAEncryption、RSASSA-PSS、ecdsa-with-SHA256、ecdsa-with-SHA384)。RSASSA-PSS 线路名称不编码摘要,因此存在摘要歧义。AwsKmsSigner 通过 KmsSigningAlgorithm::resolveForWireName() 解析它,该方法保留所配置 PSS 变体的摘要。AzureKeyVaultSigner 对该歧义名称信任所配置的 PSS 变体。若解析出的 PSS 摘要会与所配置的产生分歧,它会引发 UnsupportedAlgorithmException。GcpKmsSigner 在每次调用时都从线路名称重新解析枚举;GCP 上的 withAlgorithm() 是配置期预览,不会改变签名时行为。不受支持的线路名称会在任何网络调用之前引发 UnsupportedAlgorithmException。在 AwsKmsSigner 与 GcpKmsSigner 上,一次 sign 调用会将随后由 getSigningAlgorithm() 报告的值更新为该次调用所解析的算法。在 AzureKeyVaultSigner 上,解析是调用局部的,所配置的值仍具权威性。
签名规范化
标题为“签名规范化”的章节AWS 与 GCP 以 CMS 可消费的形式返回签名:RSA 签名字节原样进入 SignerInfo.signature,ECDSA 则以 DER 编码到达。Azure 以原始 IEEE P1363(r||s)形式返回 ECDSA,签名器在返回前将其转换为 DER ECDSA-Sig-Value。
CMS 集成与邻接面
标题为“CMS 集成与邻接面”的章节一个 SigningStrategy 适配器对会话提供的 DER 编码已签名属性进行签名。在存在已签名属性时,CMS 签名输入是 SignedAttrs 值完整 DER 编码的摘要 —— RFC 5652 §5.4。适配器的 getSignatureAlgorithmOid() 与 getDigestAlgorithm() 供给 SignerInfo 的 signatureAlgorithm 与 digestAlgorithm 字段 —— RFC 5652 §5.3。返回的字节成为 SignerInfo 签名 OCTET STRING —— 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:AWS 的NotFoundException、DisabledException、KeyUnavailableException、InvalidKeyUsageException或 HTTP 404;Azure 的 HTTP 404、KeyNotFound、KeyDisabled或KeyNotActive;GCP 的 HTTP 404 或 409、NOT_FOUND、FAILED_PRECONDITION,或一个消息中指名某版本的 HTTP 400。 - 其他非 200 的提供商响应在 AWS 与 GCP 上引发
SignatureFailedException,在 Azure 上引发AzureKeyVaultException。 - 签名期间的 PSR-18 传输失败映射到
SignatureFailedException,并将客户端异常保留为前置的可抛出对象。 AzureKeyVaultSigner在既无访问令牌又无服务主体凭据时,会在任何 vault 调用之前引发AzureKeyVaultException。Azure AD 令牌获取失败同样引发AzureKeyVaultException。AzureKeyVaultSigner在请求瓶颈处针对 Azure 公布的语法校验 vault 名称、key 名称、key 版本与 tenant id。带有 URL 结构性字符的值以AzureKeyVaultException方式 fail-closed。GcpKmsSigner在没有 OAuth2 bearer 令牌时引发SignatureFailedException;令牌获取是调用方的职责。- 不是有效 JSON、或缺少签名字段的提供商响应引发
SignatureFailedException(Azure:缺少value字段引发AzureKeyVaultException)。 - 未通过 base64 解码的提供商签名字段在 AWS 与 GCP 上引发
SignatureFailedException,在 Azure 上引发AzureKeyVaultException。 - 3.1.0 未提供针对
GcpKmsSigner的SigningStrategy适配器。GCP 签名器直接通过KmsSignerInterface契约消费。
FIPS 模式行为
标题为“FIPS 模式行为”的章节AwsKmsConfig::withFipsEndpoint() 将请求路由到该区域的 kms-fips 端点。该端点的 FIPS 验证状态是 AWS 的属性,而非 NextPDF 的。AzureKeyVaultConfig 与 GcpKmsConfig 在 3.1.0 中未暴露专用的 FIPS 端点辅助方法。摘要计算在进程内以 PHP 的 hash() 函数运行,其本身不是一个经验证的模块。NextPDF Pro 可以对接一个经 FIPS 验证的 KMS 或 HSM 边界运行,但 NextPDF 本身不是经 FIPS 验证的密码模块,且不作任何 FIPS 认证声明。
合规性
标题为“合规性”的章节| 声明 | 标准 | 条款 |
|---|---|---|
| 策略对 DER 编码的已签名属性进行签名;CMS 签名输入摘要覆盖 SignedAttrs 的完整 DER 编码。 | 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。不需要也不捆绑任何 AWS、Azure 或 Google SDK。
- 在签名前探测
supportsAlgorithm(),以便在选择时而非会话中途拒绝不兼容的提供商。 - 凭据字段经构造函数注入,并标记为敏感参数。日志消息仅携带结构性字段;不会将任何凭据、令牌或文档内容写入日志。
- 在受监管的部署中显式固定密钥版本。别名解析(AWS)与最新已启用(Azure)默认值虽便利,但在轮换之间并不确定。
- 第三方驱动实现
KmsSignerInterface,且必须为其providerId()加命名空间,以避免与保留的内置标识符冲突。
另请参阅
标题为“另请参阅”的章节- 云 KMS 签名(能力) —— 操作指南页:设置、配置与密钥托管边界。
- 安全 — 深度参考 ——
RemoteSigningSession、SequentialSigner、PAdES B-B/B-T 面,以及SigningStrategy契约。 - 签名 — 深度参考(Enterprise) —— B-LT/B-LTA 长期生产者边界。
- 安全 / 签名(Core) —— Core CMS 签名器以及本面所扩展的契约。
发布边界
标题为“发布边界”的章节本页仅记录外部可观测的行为与受支持的公共 API 面。内部命名空间路径、辅助类、机制表、运维手册文件名与工单前缀均不在范围内。