跳转到内容
getnextpdf.com

Pro 版本

云 KMS 签名 — 深度参考

本页是 NextPDF Pro 云 KMS 签名面的契约级参考。该面由一个服务提供者接口 NextPDF\Pro\Security\Signing\Kms\KmsSignerInterface 和三个提供商签名器组成:AwsKmsSignerAzureKeyVaultSignerGcpKmsSigner。两个适配器 AwsKmsSigningStrategyAzureKeyVaultSigningStrategy 将签名器桥接到 Pro 的 SigningStrategy 契约。每个签名器只把一个消息摘要通过 PSR-18 HTTP 发送给其提供商。私钥与文档从不跨越该边界。本页阐述公共 API、可观测的行为契约,以及有类型的失败模式。会话编排(RemoteSigningSessionSequentialSigner)与时间戳(PadesBtTimestamper)在各自的页面中说明。

此能力随 NextPDF Pronextpdf/pro)交付,并以 Pro 级许可证信封激活。缺少该授权的部署不会加载此能力的类。比较版本并获取许可证

符号参数默认行为返回抛出或失败于备注
KmsSignerInterface扩展 Core 的 HsmSignerInterface 契约KMS 与 HSM 驱动的 SPI;保留的内置 id:aws-kmsazure-keyvaultgcp-kmspkcs11openssl-cli
KmsSignerInterface::providerId()稳定的注册表查找键non-empty-string第三方驱动必须为其标识符加命名空间
KmsSignerInterface::signWithVersion()$data$algorithm = 'sha256WithRSAEncryption'$keyVersion = nullnull 密钥版本回退到提供商默认值string 签名字节:RSA 按提供商返回原样(直接放入 SignerInfo.signature),ECDSA 为符合 CMS 规则的 DER ECDSA-Sig-ValueKeyManagementExceptionUnsupportedAlgorithmExceptionSignatureFailedException各提供商的 null 语义不同;参见行为契约
KmsSignerInterface::supportsAlgorithm()string $algorithm能力探测;不执行任何 I/Obool在提供商选择之前调用
KmsSignerInterface::supportedAlgorithms()列出提供商接受的 OpenSSL 风格名称list<non-empty-string>
AwsKmsSigner构造函数:AwsKmsConfig、cert DER、chain DER、PSR-18 客户端、PSR-17 工厂、PSR-3 日志器算法默认为 KmsSigningAlgorithm::RsaPkcs1Sha256参见各方法finalPROVIDER_ID = 'aws-kms'
AwsKmsSigner::create()key id、cert DER、PSR 依赖项、可选 chain、config、logger$confignull 时构建 AwsKmsConfig::fromEnvironment($keyId)self读取标准的 AWS_* 环境变量
AwsKmsSigner::withAlgorithm()KmsSigningAlgorithm $algorithm返回一个修改后的克隆self必须与 AWS KMS 中预置的密钥类型匹配
AwsKmsSigner::sign()$data$algorithm = 'sha256WithRSAEncryption'委托给 signWithVersion($data, $algorithm, null)stringsignWithVersion()遗留的双参数 Core 契约路径
AzureKeyVaultSigner构造函数:AzureKeyVaultConfig、cert DER、chain DER、PSR-18 客户端、PSR-17 工厂、PSR-3 日志器算法默认为 AzureSigningAlgorithm::Rs256;config 中的访问令牌为 bearer 令牌提供初始值参见各方法finalPROVIDER_ID = 'azure-keyvault'
AzureKeyVaultSigner::create()vault 名称、key 名称、cert DER、PSR 依赖项、可选 chain、config、logger$confignull 时构建 AzureKeyVaultConfig::fromEnvironment()self支持预先获取的令牌或服务主体凭据
AzureKeyVaultSigner::withAlgorithm()AzureSigningAlgorithm $algorithm返回一个修改后的克隆selfRSA 密钥使用 RS/PS 值;EC 密钥使用 ES 值
GcpKmsSigner构造函数:GcpKmsConfig、cert DER、chain DER、PSR-18 客户端、PSR-17 工厂、PSR-3 日志器算法默认为 GcpKmsSigningAlgorithm::RsaSignPkcs1_2048Sha256参见各方法finalPROVIDER_ID = 'gcp-kms'API_VERSION = 'v1'
GcpKmsSigner::create()project id、location、key ring、crypto key、cert DER、PSR 依赖项、可选 chain、config、logger$confignull 时构建 GcpKmsConfig::fromEnvironment()selfBearer 令牌的获取委托给调用方
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()InvalidArgumentExceptionresolveForWireName() 保留所配置的 PSS 摘要
AzureSigningAlgorithm枚举,9 个成员(RS256ES512Azure Key Vault JWA 风格值来自 fromOpenSslName()InvalidArgumentExceptionisEcdsa() 标记其输出需要 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'): string
public 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): self
public 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): self
public function __construct(
private AwsKmsSigner $signer,
) {}
public function sign(string $signedAttributesDer): string
public 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 接受五个(sha256WithRSAEncryptionsha512WithRSAEncryptionRSASSA-PSSecdsa-with-SHA256ecdsa-with-SHA384)。RSASSA-PSS 线路名称不编码摘要,因此存在摘要歧义。AwsKmsSigner 通过 KmsSigningAlgorithm::resolveForWireName() 解析它,该方法保留所配置 PSS 变体的摘要。AzureKeyVaultSigner 对该歧义名称信任所配置的 PSS 变体。若解析出的 PSS 摘要会与所配置的产生分歧,它会引发 UnsupportedAlgorithmExceptionGcpKmsSigner 在每次调用时都从线路名称重新解析枚举;GCP 上的 withAlgorithm() 是配置期预览,不会改变签名时行为。不受支持的线路名称会在任何网络调用之前引发 UnsupportedAlgorithmException。在 AwsKmsSignerGcpKmsSigner 上,一次 sign 调用会将随后由 getSigningAlgorithm() 报告的值更新为该次调用所解析的算法。在 AzureKeyVaultSigner 上,解析是调用局部的,所配置的值仍具权威性。

AWS 与 GCP 以 CMS 可消费的形式返回签名:RSA 签名字节原样进入 SignerInfo.signature,ECDSA 则以 DER 编码到达。Azure 以原始 IEEE P1363(r||s)形式返回 ECDSA,签名器在返回前将其转换为 DER ECDSA-Sig-Value

一个 SigningStrategy 适配器对会话提供的 DER 编码已签名属性进行签名。在存在已签名属性时,CMS 签名输入是 SignedAttrs 值完整 DER 编码的摘要 —— RFC 5652 §5.4。适配器的 getSignatureAlgorithmOid()getDigestAlgorithm() 供给 SignerInfo 的 signatureAlgorithmdigestAlgorithm 字段 —— 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 以继承所配置的默认值。
  • 格式错误的密钥版本会在构建任何请求之前被拒绝,并在异常中指明违规的值。
  • AwsKmsSignerAwsKmsConfig::$keyId 为空且密钥版本为 null 时引发 KeyManagementException
  • 表示密钥管理失败的提供商响应映射到 KeyManagementException:AWS 的 NotFoundExceptionDisabledExceptionKeyUnavailableExceptionInvalidKeyUsageException 或 HTTP 404;Azure 的 HTTP 404、KeyNotFoundKeyDisabledKeyNotActive;GCP 的 HTTP 404 或 409、NOT_FOUNDFAILED_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 未提供针对 GcpKmsSignerSigningStrategy 适配器。GCP 签名器直接通过 KmsSignerInterface 契约消费。

AwsKmsConfig::withFipsEndpoint() 将请求路由到该区域的 kms-fips 端点。该端点的 FIPS 验证状态是 AWS 的属性,而非 NextPDF 的。AzureKeyVaultConfigGcpKmsConfig 在 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 3161Appendix A

所有条款均为释义;NextPDF 不复制规范性文本。这些是能力陈述,而非认证。NextPDF 不持有任何认证,也不授予任何认证。所产生的签名是否验证通过,是验证方依据其自身信任锚与策略作出的决定;签名器返回签名字节,不断言任何受信任的结果。密钥托管、密钥保护与提供商侧的算法验证是所配置 KMS 的属性,而非 NextPDF 的。

  • Pro 包内的可用性:AwsKmsSigner 自 1.9.0 起,AzureKeyVaultSigner 自 2.0.0 起,GcpKmsSignerKmsSignerInterface 自 2.1.0 起。三者在 nextpdf/pro 3.1.0 中均为最新。
  • 这些签名器仅依赖 PSR-18、PSR-17 与 PSR-3。不需要也不捆绑任何 AWS、Azure 或 Google SDK。
  • 在签名前探测 supportsAlgorithm(),以便在选择时而非会话中途拒绝不兼容的提供商。
  • 凭据字段经构造函数注入,并标记为敏感参数。日志消息仅携带结构性字段;不会将任何凭据、令牌或文档内容写入日志。
  • 在受监管的部署中显式固定密钥版本。别名解析(AWS)与最新已启用(Azure)默认值虽便利,但在轮换之间并不确定。
  • 第三方驱动实现 KmsSignerInterface,且必须为其 providerId() 加命名空间,以避免与保留的内置标识符冲突。

本页仅记录外部可观测的行为与受支持的公共 API 面。内部命名空间路径、辅助类、机制表、运维手册文件名与工单前缀均不在范围内。