Pro 에디션
Cloud 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()과 동일 | 레거시 2-인수 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 name, key name, 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 | config 시점의 미리보기 전용; 서명 시점에는 호출별 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) | — | AWS KMS SigningAlgorithm wire 값 | fromOpenSslName()의 InvalidArgumentException | resolveForWireName()은 구성된 PSS 다이제스트를 보존 |
AzureSigningAlgorithm | enum, 9개 케이스 (RS256…ES512) | — | Azure Key Vault JWA 스타일 값 | fromOpenSslName()의 InvalidArgumentException | isEcdsa()는 출력에 DER 변환이 필요한 값을 표시 |
GcpKmsSigningAlgorithm | enum, 10개 케이스 (EC P-256/P-384, RSA PKCS#1, RSA-PSS) | — | GCP CryptoKeyVersion 알고리즘 값 | fromOpenSslName()의 UnsupportedAlgorithmException | 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() 기능 탐지를 추가합니다. 상속된 2-인수 sign()은 세 서명자 모두에서 null 키 버전으로 signWithVersion()에 위임합니다. getCertificateDer(), getCertificateChainDer(), getPublicKeyAlgorithm()은 생성자로 공급된 자료로부터 구현됩니다. 기능 탐지는 I/O를 수행하지 않습니다. 각 서명자는 검사를 위한 getSigningAlgorithm()과 getConfig() 접근자도 노출합니다.
다이제스트 전용 전송
섹션 제목: “다이제스트 전용 전송”각 서명자는 해석된 알고리즘의 다이제스트로 $data를 로컬에서 해시하고 그 다이제스트만을 전송합니다. AWS는 MessageType: DIGEST와 함께 base64 다이제스트를 받습니다. Azure는 sign 요청 본문에서 base64url 다이제스트를 받습니다. GCP는 알고리즘별 다이제스트 필드에서 base64 다이제스트를 받습니다. 문서 바이트는 프로바이더 요청에 절대 나타나지 않습니다. 모든 전송은 프로바이더의 HTTPS 엔드포인트를 통해 표준 PSR-18 HTTP 클라이언트를 사용하며, 어떤 클라우드 벤더 SDK도 관여하지 않습니다.
키 버전 해석
섹션 제목: “키 버전 해석”signWithVersion()은 어떤 요청도 빌드되기 전에 키 버전 인수를 fail-closed 방식으로 검증합니다. 프로바이더 문법에 실패하는 값은 KeyManagementException을 발생시키고 URL 세그먼트 또는 KeyId 주입을 방지합니다.
| 프로바이더 | null 키 버전 | 빈 문자열 | 재정의 문법 |
|---|---|---|---|
AwsKmsSigner | AwsKmsConfig::$keyId를 사용; 별칭 또는 ARN은 프로바이더 측에서 현재 키로 해석됨 | 거부됨 | UUID(대시 포함 또는 미포함), alias/<name>, 또는 KMS key/alias ARN |
AzureKeyVaultSigner | 구성된 키 버전을 사용; 빈 config 값은 서버 측에서 활성화된 최신 버전을 선택 | 거부됨 | 32자 16진수 식별자 |
GcpKmsSigner | GcpKmsConfig에 고정된 버전을 사용; 고정된 것이 없으면 KeyManagementException 발생 | 거부됨 | 10진수 CryptoKeyVersion id, 숫자만 |
GCP에는 서버 측 “활성 버전” 프리미티브가 없습니다. 비대칭 sign 엔드포인트는 특정 cryptoKeyVersions/{n} 리소스에서만 작동하므로, 버전은 항상 해석 가능해야 합니다.
알고리즘 해석
섹션 제목: “알고리즘 해석”전략 계층은 OpenSSL 스타일 wire 이름을 전달합니다. AWS와 Azure는 7개의 wire 이름(SHA-256/384/512의 PKCS#1과 ECDSA, 그리고 RSASSA-PSS)을 허용합니다. GCP는 5개(sha256WithRSAEncryption, sha512WithRSAEncryption, RSASSA-PSS, ecdsa-with-SHA256, ecdsa-with-SHA384)를 허용합니다. RSASSA-PSS wire 이름은 다이제스트를 인코딩하지 않으므로 다이제스트가 모호합니다. AwsKmsSigner는 이를 KmsSigningAlgorithm::resolveForWireName()을 통해 해석하며, 이는 구성된 PSS 변형의 다이제스트를 보존합니다. AzureKeyVaultSigner는 모호한 이름에 대해 구성된 PSS 변형을 신뢰합니다. 해석된 PSS 다이제스트가 구성된 것과 달라지면 UnsupportedAlgorithmException을 발생시킵니다. GcpKmsSigner는 호출마다 wire 이름에서 enum을 다시 해석합니다; GCP의 withAlgorithm()은 config 시점의 미리보기이며 서명 시점 동작을 바꾸지 않습니다. 지원되지 않는 wire 이름은 어떤 네트워크 호출보다 먼저 UnsupportedAlgorithmException을 발생시킵니다. AwsKmsSigner와 GcpKmsSigner에서는 sign 호출이 이후 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 서명 입력은 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에 속합니다. messageImprint가 SignerInfo 서명 값을 해시하는 PAdES B-T 서명 타임스탬프 — RFC 3161 Appendix A — 는 이 서명자들이 아니라 PadesBtTimestamper에 의해 적용됩니다. 셋 모두 Pro 보안 심화 레퍼런스에 문서화되어 있습니다.
엣지 케이스 및 실패 모드
섹션 제목: “엣지 케이스 및 실패 모드”- 빈 문자열 키 버전은 세 프로바이더 모두에서 거부됩니다. 구성된 기본값을 상속하려면
null을 전달하세요. - 잘못된 형식의 키 버전은 어떤 요청도 빌드되기 전에 거부되며, 문제가 되는 값이 예외에 명시됩니다.
- 빈
AwsKmsConfig::$keyId와null키 버전을 가진AwsKmsSigner는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이 아닌 프로바이더 응답은 AWS와 GCP에서
SignatureFailedException을, Azure에서AzureKeyVaultException을 발생시킵니다. - 서명 중 PSR-18 전송 실패는 클라이언트 예외를 이전 throwable로 보존한 채
SignatureFailedException으로 매핑됩니다. - 액세스 토큰과 서비스 주체 자격 증명이 모두 없는
AzureKeyVaultSigner는 어떤 vault 호출보다 먼저AzureKeyVaultException을 발생시킵니다. Azure AD 토큰 획득 실패도AzureKeyVaultException을 발생시킵니다. AzureKeyVaultSigner는 요청 초크포인트에서 vault name, key name, key version, tenant id를 Azure가 게시한 문법에 대해 검증합니다. URL 구조적 문자를 담은 값은AzureKeyVaultException으로 fail-closed됩니다.- OAuth2 bearer 토큰이 없는
GcpKmsSigner는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 검증 상태는 NextPDF가 아니라 AWS의 속성입니다. 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는 어떤 인증도 보유하지 않으며 어떤 것도 부여하지 않습니다. 생성된 서명이 검증되는지 여부는 검증자가 자체 신뢰 앵커와 정책에 대해 내리는 결정입니다; 서명자는 서명 바이트를 반환하며 신뢰할 수 있는 결과를 주장하지 않습니다. 키 보관, 키 보호, 프로바이더 측 알고리즘 검증은 NextPDF가 아니라 구성된 KMS의 속성입니다.
개발 참고 사항
섹션 제목: “개발 참고 사항”- 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 표면만을 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 테이블, 런북 파일명, 티켓 접두사는 범위 밖입니다.