콘텐츠로 이동

보안 / 서명: CMS, RFC 3161 타임스탬프, LTV, 신뢰

이 페이지는 NextPDF Core에 포함되어 제공되는 서명 영역을 설명합니다. 구체적으로 CMS 서명을 생성하고, RFC 3161 타임스탬프를 적용하며, RFC 5280에 따라 인증서 체인을 검증하고, OCSP 및 CRL을 통해 폐기 상태를 확인하는 동작을 다룹니다. 이는 동작 수준의 설명입니다. Core 구현 클래스는 내부용입니다. 프로덕션 코드는 SignerInterface 계약을 사용하며, 구체적인 NextPDF\Security\Signature 타입은 사용하지 않습니다. 생성된 서명이 검증되는지 여부는 검증자와 검증자에 구성된 신뢰 앵커에 의해 결정됩니다. 그 결과는 생성자의 통제 밖에 있으며, 이 페이지는 중요한 지점마다 이를 명시합니다.

Terminal window
composer require nextpdf/core:^3

Core는 바이트 범위로부터 CMS SignedData 구조를 만든 다음, 이를 DER로 인코딩하여 서명 딕셔너리의 Contents 항목에 저장합니다 — ISO 32000-2 §12.8.1. 이 구조에는 SignerInfo 서명된 속성이 포함되며, 그중에는 content-type과 message-digest가 있습니다 — RFC 5652 §5.3. 검증자는 콘텐츠 다이제스트를 다시 계산하여 message-digest 속성과 비교합니다. 서명이 유효하려면 이 비교 결과가 일치해야 합니다 — RFC 5652 §5.4. SignerInfo는 다이제스트 알고리즘 식별자와 서명된 속성 블록도 포함합니다 — RFC 5652 §5. Core는 자체적으로 제공하는 소프트웨어 경로에서 phpseclib3을 통해 서명합니다. 즉 RSA, RSASSA-PSS, ECDSA, Ed25519입니다.

RFC 3161 타임스탬프는 TSTInfo 구조를 반환하는 타임스탬프 기관(Time-Stamping Authority)과의 요청-응답 교환입니다 — RFC 3161 §2.4.1. 각 토큰은 발급 TSA에 고유한 serialNumber를 포함하며 — RFC 3161 §2.4.2 — 토큰이 생성된 순간을 UTC로 표현한 genTime도 포함합니다 — RFC 3161 §2.4.2.

신뢰 검증은 두 가지 확인으로 이루어집니다. 경로 검증은 서명자 인증서에서 신뢰 앵커까지 따라가면서 기본 제약 조건과 경로 구성 입력을 확인합니다 — RFC 5280 §6.1. 폐기 확인은 OCSP 응답자에게 질의하거나 CRL을 읽습니다. OCSP 응답은 good, revoked, 또는 unknown을 보고하며 — RFC 6960 §2.2 — 응답의 thisUpdatenextUpdate가 해당 상태의 최신성을 제한합니다 — RFC 6960 §4.2. 신뢰 앵커와 폐기 최신성 정책은 호출자가 제공합니다. 엔진은 제공된 입력을 기준으로 검증하며 내장 신뢰 목록을 제공하지 않습니다.

타입종류역할안정성도입 버전
SignerInterfaceinterface (NextPDF\Contracts)호출자가 의존하는 서명 계약stable (안정)1.0.0
SignatureLevelenumPAdES 레벨 선택자 및 사용 가능 여부 탐지stable (안정)1.0.0
Rfc5280PathValidatorinterface인증 경로 검증 진입점 (validate(...))stable (3.1.0에서 동결됨)3.1.0
RevocationStatusenumOCSP / CRL 결과: good, revoked, unknownstable (안정)3.1.0
CaTrustAnchorBundletype (타입)호출자가 제공하는 신뢰 앵커 집합stable (안정)3.1.0
TstInfotype (타입)파싱된 RFC 3161 타임스탬프 필드stable (안정)3.2.0

SignerInterface::sign()SignatureResult를 반환하며, 그 toHex()/Contents 16진수 문자열을 산출하고, cmsSignedData 속성은 원시 DER 바이트를 담습니다. 이러한 동작을 구현하는 구체적인 NextPDF\Security\Signature 클래스는 내부용입니다(모듈 매니페스트에서 stability: internal). 이들은 공개 API의 일부가 아니며 메이저 버전 증가 없이 변경될 수 있습니다. 위의 계약과 enum에 의존하십시오.

examples/contracts/signing-quickstart.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/**
* Produce the CMS SignedData hex for a PDF /Contents field.
*
* @param SignerInterface $signer A Core or Premium signer.
* @param string $byteRange The PDF byte range to sign.
*
* @return string Hex-encoded CMS SignedData.
*/
function sign(SignerInterface $signer, string $byteRange): string
{
return $signer->sign($byteRange)->toHex();
}

호출자는 계약에 의존합니다. Core 소프트웨어 서명자와 Premium HSM 서명자 모두 SignerInterface를 충족하므로, 이 코드는 에디션 전반에서 변경되지 않습니다.

examples/contracts/signing-trust.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
use NextPDF\Contracts\TimestampProviderInterface;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
final readonly class TimestampedSigner
{
public function __construct(
private SignerInterface $signer,
private TimestampProviderInterface $timestamps,
private LoggerInterface $logger,
) {}
/**
* Sign a byte range, then timestamp the CMS structure.
*
* The timestamp's trust still depends on the verifier accepting the
* Time-Stamping Authority; this method only produces the structure.
*
* @param string $byteRange The PDF byte range to sign.
*
* @return array{cms: string, tst: string}
*/
public function sign(string $byteRange): array
{
try {
$signature = $this->signer->sign($byteRange);
$token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return ['cms' => $signature->toHex(), 'tst' => $token];
} catch (NextPdfException $e) {
$this->logger->error('Signing failed', ['error' => $e->getMessage()]);
throw $e;
}
}
}

타임스탬프 공급자는 주입되므로, 배포 환경은 자체 타임스탬프 기관(Time-Stamping Authority)을 고정합니다. catch 블록은 로그를 남기고 다시 던집니다. 이는 실패를 결코 삼키지 않으므로, 서명 경로를 fail-closed로 유지합니다.

  • 생성된 서명은 검증된 서명이 아닙니다. 경로 검증과 폐기 확인은 검증자의 신뢰 앵커를 사용해 검증자 측에서 실행됩니다. 생성자는 그 결과를 단언할 수 없습니다.
  • 바이트 범위 다이제스트는 서명 값을 제외합니다. Contents 옥텟을 포함하는 다이제스트는 검증될 수 없습니다 — ISO 32000-2 §12.8.1.
  • 폐기 상태에는 최신성 기간이 있습니다. OCSP 응답은 그 thisUpdate / nextUpdate 간격 동안만 최신입니다 — RFC 6960 §4.2. 오래된 응답은 검증 시점의 최신 확인을 대체하지 못합니다.
  • 엔진은 내장 신뢰 목록을 제공하지 않습니다. CaTrustAnchorBundle은 호출자가 제공합니다. 빈 번들은 설계상 어떤 체인도 검증되지 않음을 의미합니다.
  • OCSP unknowngood이 아닙니다. unknown은 암묵적 통과가 아니라 미확정으로 처리하십시오 — RFC 6960 §2.2.
  • HSM 키 보관, 지연 및 클라우드 서명, 그리고 PAdES B-LT / B-LTA 생성기는 Core에 포함되지 않습니다. Core 배포판에서 이러한 경로를 선택하면 누락된 Enterprise 구성 요소를 명시하는 메시지와 함께 fail-closed로 실패합니다.

소프트웨어 서명은 한 자릿수 밀리초 안에 수행됩니다. 타임스탬프는 TSA로의 네트워크 왕복을 한 번 추가합니다. 인증서가 메모리에 있으면 경로 검증은 로컬에서 수행됩니다. 폐기 확인은 체인의 인증서마다 OCSP 또는 CRL 가져오기를 한 번씩 추가합니다. 1500 ms의 실시간 예산은 따뜻한 연결에서 원격 TSA를 사용한 단일 타임스탬프 서명을 포함합니다. 느린 엔드포인트에 대한 폐기 확인은 이를 초과하므로 요청 경로 밖에 두어야 합니다. 재현성 프로필은 structural입니다. 타임스탬프는 서명 순간을 포함하므로, 두 번의 실행은 문서 구조가 동일하더라도 타임스탬프 바이트에서 차이가 납니다.

이는 엔진의 주요 암호화 경계이므로 위협 모델이 명시되어 있습니다. 바이트 범위는 엔진이 계산하며 호출자로부터 받아들이지 않습니다. 서명 경로는 fail-closed입니다. 프리미티브 실패 또는 기능 부재는 타입이 지정된 예외를 발생시키며, 결코 더 약한 알고리즘으로 조용히 다운그레이드하지 않습니다. 타임스탬프가 요구되는 레벨(B-T, B-LT, B-LTA)에서 빈 토큰을 반환하는 타임스탬프 기관(Time-Stamping Authority)은 종단 결함입니다. 즉, 문서화된 성능 저하를 승인하도록 결함 핸들러가 연결되어 있지 않는 한, 서명은 조용히 타임스탬프가 없는 다운레벨 상태로 발행되지 않고 거부됩니다. 신뢰는 설계상 호출자가 제어합니다. 앵커와 폐기 정책은 엔진 기본값이 아니라 입력입니다. 자체 신뢰를 단언하는 생성자는 검증자만이 확립할 수 있는 사실을 단언하는 것이기 때문입니다. 타임스탬프 신뢰는 타임스탬프 기관(Time-Stamping Authority)에 대한 신뢰로 귀결되며, 이는 주입 가능하므로 배포 환경은 자체 기관을 고정합니다. 이 페이지는 암호화 서명과 관련되므로 export_control_class: legal-review-required로 표시되어 있습니다. 인용 위생 원칙에 따라 모든 규범적 출처는 의역되며 어느 것도 그대로 복제되지 않습니다.

주장표준조항증거
CMS 서명은 DER로 인코딩되어 서명 딕셔너리의 Contents 항목에 저장됩니다.ISO 32000-2§12.8.1
SignerInfo는 content-type 및 message-digest 서명된 속성을 포함합니다.RFC 5652§5.3
검증자는 콘텐츠 다이제스트를 다시 계산하여 message-digest 속성과 비교합니다.RFC 5652§5.4
타임스탬프 토큰은 RFC 3161 TSA가 생성하며, 고유한 serialNumber와 UTC genTime을 포함합니다.RFC 3161§2.4.1, §2.4.2,,
인증 경로 검증은 서명자에서 신뢰 앵커까지의 기본 제약 조건과 경로 입력을 확인합니다.RFC 5280§6.1,
OCSP는 certStatus를 good, revoked, 또는 unknown으로 보고하며, thisUpdate / nextUpdate에 의해 제한됩니다.RFC 6960§2.2, §4.2,

모든 조항은 의역되었습니다. NextPDF는 규범적 텍스트를 복제하지 않습니다. 권위 있는 표현은 발행된 표준을 참조하십시오.

Core는 소프트웨어 CMS 서명자(RSA, RSASSA-PSS, ECDSA, Ed25519), RFC 3161 타임스탬프 사용, RFC 5280 경로 검증, 그리고 OCSP / CRL 폐기 확인을 제공합니다. HSM 및 PKCS#11 키 보관, 지연 및 클라우드 서명, PAdES B-LT 및 B-LTA 생성기, 그리고 FIPS 140-3 암호화 정책 프로필은 Pro 및 Enterprise 에디션에서 제공됩니다. Core는 런타임에 계약에 따라 이들을 해석하므로, 오픈소스 엔진은 상업적 의존성을 갖지 않으며 업그레이드 시 API가 변경되지 않습니다.