콘텐츠로 이동
getnextpdf.com

Enterprise 에디션

eIDAS 보증 수준

NextPDF Enterprise는 EU 신뢰 목록 증거를 명시적인 eIDAS 보증 수준(LoA)으로 변환합니다. NextPDF\Enterprise\Security\Eidas\LoaMapping 서비스는 하나의 신뢰 서비스 항목을 Low, Substantial, 또는 High 로 분류합니다. 이는 해당 수준과 함께 기계 판독 가능한 사유 코드를 담은 LoaAssertion 을 반환합니다. 여러분의 워크플로는 보증을 기준으로 게이트를 걸 수 있으며 — “High 를 요구” — 그 사유들을 감사 증거로 보관할 수 있습니다. 동반 가드인 CertPiiGuard 는 감사 레코드가 프로세스를 떠나기 전에 서명자 신원 필드를 편집합니다.

두 가지 경계가 이 기능을 정직하게 규정합니다. 첫째, 적격성(qualification)은 언제나 회원국 감독하에 있는 신뢰 서비스 제공자(TSP)에게 속합니다. NextPDF는 게시된 증거에 대한 분류를 단언할 뿐이며, 적격성을 부여하거나 수여하거나 인증하지 않습니다. 둘째, 이 페이지는 LoA 단언과 매핑만을 다룹니다. 통과/실패 기준을 포함한 구조적 PAdES 정책 eidasQualified()Validation에 문서화되어 있습니다.

이 기능은 NextPDF Enterprise (nextpdf/enterprise)에서 제공되며 Enterprise 등급 라이선스 엔벨로프로 활성화됩니다. 해당 권한이 없는 배포에서는 이 기능의 클래스가 로드되지 않습니다. 에디션 비교 및 라이선스 받기.

Terminal window
composer require nextpdf/enterprise

nextpdf/premium 메타패키지 역시 Enterprise 패키지를 해결합니다. 활성화는 여러분의 Enterprise 라이선스 엔벨로프를 사용합니다. Licensing and activation을 참조하세요. eIDAS 클래스는 엔진 기준선 외에 별도의 PHP 확장을 필요로 하지 않습니다. 이들은 NextPDF\Enterprise\Security\EidasNextPDF\Enterprise\Signature\Eidas 아래에서 오토로드됩니다.

Regulation (EU) No 910/2014 (eIDAS)는 세 가지 보증 수준을 정의합니다: low, substantial, 그리고 high (Article 8(1)). 각 수준은 주장된 신원에 대한 신뢰의 정도를 표현합니다. Level high는 신원 오용 또는 변조를 단지 줄이는 것이 아니라 방지하는 것을 목적으로 하는 통제를 추가합니다 (Article 8(2)(c)). Article 8은 이 수준들을 전자 식별 체계에 대해 정의합니다. NextPDF는 서명 인증서 뒤에 있는 신뢰 서비스 증거를 분류하기 위해 동일한 어휘를 재사용합니다. 그 재사용은 정책 게이팅과 감사를 위한 엔지니어링 관례이며, 법적 등가성이 아닙니다.

LoaLevel 열거형은 세 가지 수준을 모델링합니다. 그 백업 값은 단순한 레이블이 아니라 eIDAS LoA URI이므로, 지속화된 단언은 완전한 식별자를 담습니다. rank() 는 전순서를 부여하며 (Low = 1, Substantial = 2, High = 3), meetsOrExceeds() 는 요구되는 하한과 비교합니다.

LoaMapping 은 하나의 신뢰 목록 항목 — Enterprise 신뢰 목록 하위 시스템(NextPDF\Enterprise\Security\Tsl)에서 나온 TspService — 으로부터 수준을 계산합니다. 매핑은 결정적입니다:

신뢰 목록 증거수준사유 코드
서비스 상태가 granted 가 아님Lowservice_not_granted
서비스 유형이 CA/QC 가 아님Lowservice_not_qualified_ca
QCWithQSCD 를 갖고 QCNoQSCD 는 없는 granted CA/QCHighca_qc_with_qscdesig_or_eseal 또는 qc_default
그 밖의 granted CA/QCSubstantialca_qc_no_qscd_or_unspecified

QSCD(적격 서명 생성 장치) 한정자가 중심축입니다. Article 3(12)에 따라, 적격 전자 서명은 적격 인증서와 적격 생성 장치를 모두 요구합니다. 따라서 인증서가 QSCD에서 관리된다는 신뢰 목록 진술은 High 단언을 뒷받침하는 증거입니다. 그 진술이 없으면, granted 적격 CA라 하더라도 여전히 Substantial 을 뒷받침하며 결코 High 는 아닙니다.

그 결과는 LoaAssertion 입니다: 수준과 사유 코드 목록. 그 사유들은 감사 소비자가 나중에 동일한 증거로부터 분류를 재도출할 수 있게 합니다. 하류의 정책 평가자는 서명 검증 결과와 나란히 그 단언을 기록할 수 있습니다.

이 모듈에는 한 조각이 더 포함됩니다: CertPiiGuard. 검증 아티팩트가 JSON 감사 번들로 직렬화될 때, 서명자 인증서는 개인 데이터를 담습니다 — Subject CN, 이메일 속성, 그리고 자연인의 경우 국가 식별자를 인코딩할 수 있는 serialNumber 속성. GDPR Article 5(1)(c)는 처리가 필요한 것으로 제한될 것을 요구합니다. 따라서 가드는 그 필드들을 기본으로 편집하여, 값을 [REDACTED] 로 대체하는 한편 구조적 엔벨로프(조직, 국가, 체인 및 상태 필드)는 보존합니다. 소비자는 누가 서명했는지 알지 못한 채로도 서명이 통과했는지 여부 를 여전히 검증할 수 있습니다.

부하를 지탱하는 결정은 보증 단언검증 판정으로부터 분리하는 것입니다. 서명 검증은 ETSI EN 319 102-1에 따라 상태 표시 — TOTAL-PASSED, TOTAL-FAILED, 또는 INDETERMINATE — 로 끝나며, 그 판정은 검증 계층에 속합니다. LoA 매핑은 신뢰 목록 증거에 대한 별개의 재현 가능한 분류이며, 단순한 레이블 대신 사유 코드를 갖습니다. 이는 NextPDF가 보증 주장을 검증 결과로, 또는 검증 결과를 적격성 부여로 결코 제시하지 못하게 합니다. 또한 이는 매핑을 구성상 보수적으로 만듭니다: 부재하거나 모호한 증거는 수준을 낮출 뿐 결코 높이지 않습니다.

설계 배경: Qualified signatures, explained.

아래의 모든 심볼은 nextpdf/enterprise 3.1.0의 공개 API입니다.

enum LoaLevel: string
{
case Low = 'http://eidas.europa.eu/LoA/low';
case Substantial = 'http://eidas.europa.eu/LoA/substantial';
case High = 'http://eidas.europa.eu/LoA/high';
public function rank(): int
public function meetsOrExceeds(self $required): bool
}

던지거나 실패하는 것: rank()meetsOrExceeds() 에서는 아무것도 없음. LoaLevel::from() 을 통한 네이티브 열거형 생성은 인식되지 않는 URI에서 \ValueError 를 던지며, LoaLevel::tryFrom() 은 대신 null 을 반환합니다.

final class LoaMapping
{
public function loaForService(TspService $service): LoaAssertion
}

던지거나 실패하는 것: 없음. 이 메서드는 전역적(total)입니다 — 모든 TspService 입력은 LoaAssertion 을 산출합니다.

입력 DTO인 NextPDF\Enterprise\Security\Tsl\TspServiceNextPDF\Enterprise\Security\Tsl\TspServiceQualifier 는 안정적인 공개 DTO입니다 (@api). 매핑은 TspService::STATUS_GRANTED, TspService::TYPE_CA_QC, 그리고 한정자 상수 TspServiceQualifier::QSCD_STATEMENT (QCWithQSCD), TspServiceQualifier::NO_QSCD (QCNoQSCD), TspServiceQualifier::FOR_ESIG, TspServiceQualifier::FOR_ESEAL 을 참조합니다.

final readonly class LoaAssertion
{
/**
* @param list<non-empty-string> $reasons Machine-readable reason codes for the assertion.
*/
public function __construct(
public LoaLevel $level,
public array $reasons,
) {}
}

던지거나 실패하는 것: 없음. 불변 값 객체.

final readonly class CertPiiGuard
{
public function __construct(
private bool $disclosePii = false,
) {}
public function disclosesPii(): bool
public function guardSignerCommonName(string $signer): string
public function guardDistinguishedName(string $dn): string
public function guardTsaName(string $tsaName): string
public function guardRootIssuer(string $issuer): string
public function guardChainIssue(string $issue): string
}

던지거나 실패하는 것: 없음. 가드는 순수 문자열 변환입니다. 확실하게 토큰화할 수 없는 DN 구성 요소에 대해, 가드는 부분적으로 마스킹된 값을 방출하는 대신 폐쇄 실패(fail closed)하여 그 구성 요소를 [REDACTED] 로 축소합니다.

LoA URI를 파싱하여 요구되는 하한과 비교합니다.

loa-quick-start.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Eidas\LoaLevel;
// A LoA URI as persisted in an audit record or received from a peer system.
$uri = 'http://eidas.europa.eu/LoA/substantial';
try {
$level = LoaLevel::from($uri);
} catch (\ValueError $e) {
// Unknown URI: refuse to classify. Never guess an assurance level.
echo "Unrecognized LoA URI: {$uri}\n";
exit(1);
}
echo 'Level: ' . $level->name . ' (rank ' . $level->rank() . ")\n";
echo 'Meets substantial: ' . ($level->meetsOrExceeds(LoaLevel::Substantial) ? 'yes' : 'no') . "\n";
echo 'Meets high: ' . ($level->meetsOrExceeds(LoaLevel::High) ? 'yes' : 'no') . "\n";

예상 출력:

Level: Substantial (rank 2)
Meets substantial: yes
Meets high: no

신뢰 목록 항목을 분류하고, 요구되는 수준을 기준으로 게이트를 걸며, 편집된 감사 레코드를 방출합니다.

loa-audit-gate.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Eidas\LoaLevel;
use NextPDF\Enterprise\Security\Eidas\LoaMapping;
use NextPDF\Enterprise\Security\Tsl\TspService;
use NextPDF\Enterprise\Security\Tsl\TspServiceQualifier;
use NextPDF\Enterprise\Signature\Eidas\CertPiiGuard;
// Normally produced by the Enterprise trusted-list subsystem from a
// member-state TSL; constructed inline here for a self-contained example.
$caPem = (string) file_get_contents(__DIR__ . '/example-qc-ca.pem');
$service = new TspService(
tspName: 'Example Qualified TSP',
serviceName: 'Example Qualified CA G2',
serviceTypeIdentifier: TspService::TYPE_CA_QC,
serviceStatus: TspService::STATUS_GRANTED,
statusStartingTime: '2024-01-01T00:00:00Z',
serviceCertificatePem: $caPem,
qualifiers: [
new TspServiceQualifier(qualifierUri: TspServiceQualifier::QSCD_STATEMENT),
new TspServiceQualifier(qualifierUri: TspServiceQualifier::FOR_ESIG),
],
additionalServiceInformation: [],
);
try {
// Required floor from deployment configuration; defaults to High.
$required = LoaLevel::from(getenv('LOA_REQUIRED') ?: LoaLevel::High->value);
} catch (\ValueError $e) {
echo "Invalid LOA_REQUIRED URI; refusing to continue.\n";
exit(1);
}
$mapping = new LoaMapping();
$assertion = $mapping->loaForService($service);
// Privacy by default: signer identity fields are redacted in audit output.
$guard = new CertPiiGuard();
$audit = [
'loa' => $assertion->level->value,
'reasons' => $assertion->reasons,
'meets_required' => $assertion->level->meetsOrExceeds($required),
'signer' => $guard->guardSignerCommonName('CN=Jane Example, O=Example Corp, C=DE'),
];
echo json_encode($audit, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";

예상 출력:

{
"loa": "http://eidas.europa.eu/LoA/high",
"reasons": [
"ca_qc_with_qscd",
"esig_or_eseal"
],
"meets_required": true,
"signer": "CN=[REDACTED], O=Example Corp, C=DE"
}
  • LoaLevel::from() 은 알 수 없는 URI에서 \ValueError 를 던집니다. null 처리가 더 바람직한 곳에서는 LoaLevel::tryFrom() 을 사용하세요.
  • 상충하는 장치 증거는 보수적으로 유지됩니다. QCWithQSCDQCNoQSCD 를 모두 담은 서비스는 High 가 아니라 Substantial 로 매핑됩니다.
  • 한정자가 없는 granted CA/QC 서비스는 사유 ca_qc_no_qscd_or_unspecified 와 함께 Substantial 로 매핑됩니다 — 기본적으로 적격이나 장치는 입증되지 않음.
  • 추적 대상 집합 밖의 한정자 URI는 분류에 영향을 주지 않습니다. 알 수 없거나 미래의 한정자는 결코 수준을 높이지 않습니다.
  • 매핑은 현재 서비스 상태만 읽습니다. statusStartingTime 이력을 평가하지 않으며, 특정 시점 윈도는 검증 계층에 속합니다.
  • rank() 정수가 아니라 열거형의 백업 URI를 지속화하세요. 순위(rank)는 오직 비교를 위해서만 존재합니다.
  • CertPiiGuard= 가 없는 단순한 이름을 전부 [REDACTED] 로 축소합니다. 빈 문자열은 모든 가드를 변경 없이 통과합니다.
  • 레거시 OpenSSL 슬래시 구분 DN은 감지되어 구조적으로 마스킹됩니다. RFC 4514 값 안의 / 는 구분자가 아니라 내용으로 취급됩니다.
  • 비 PII DN 속성(O, OU, C, ST, L)은 보존되므로, 편집 후에도 관할 추론은 살아남습니다.
  • 기본으로 프라이버시. 가드 생성자는 기본값이 disclosePii: false 입니다. 서명자 신원을 처리할 문서화된 적법한 근거를 보유한 곳에서만 new CertPiiGuard(disclosePii: true) 를 구성하세요. 이는 직렬화 경계에서 GDPR Article 5(1)(c) 데이터 최소화를 구현합니다.
  • 폐쇄 실패 편집. DN 구성 요소를 확실하게 토큰화할 수 없을 때, 그 구성 요소 전체가 [REDACTED] 로 축소됩니다. 프라이버시 통제는 결코 개방 실패(fail open)하지 않습니다.
  • 결정적 출력. 가드는 순수 문자열 처리를 사용합니다 — 시계도, 무작위성도 없습니다 — 그래서 마스킹된 출력은 동일한 입력에 대해 바이트 단위로 안정적입니다. 안정적인 출력은 감사 diff를 의미 있게 유지합니다.
  • 편집은 암호화가 아닙니다. [REDACTED] 는 값을 레코드에서 제거합니다. 신원을 복구 가능하게 유지해야 한다면, 그것을 자체의 적법한 근거와 접근 통제하에 별도로 저장하세요.
  • 쓰레기가 들어가면 쓰레기가 나옵니다. LoaAssertion 은 그 뒤에 있는 신뢰 목록 증거만큼만 신뢰할 수 있습니다. 항목을 매핑에 공급하기 전에 Enterprise 신뢰 목록 하위 시스템을 통해 신뢰 목록을 취득하고 서명 검사하세요.

NextPDF Enterprise는 Regulation (EU) No 910/2014 Article 8 (보증 수준)과 Article 3(12) (적격 전자 서명의 요소), 그리고 ETSI 신뢰 목록 한정자 어휘로부터 정보를 얻은 동작을 구현합니다. 지원은 적합성이 아니며, 적합성은 인증이 아닙니다. NextPDF는 어떤 인증도 보유하지 않으며 어떤 인증도 부여하지 않습니다. NextPDF는 적격 신뢰 서비스 제공자가 아니고, 적합성 평가 기관이 아니며, 감독 기관이 아닙니다. LoaAssertion 은 게시된 증거에 대한 소프트웨어 분류입니다. 그것은 적격성이나 보증에 대한 법적 결정이 아니며, 서명을 적격으로 만들 수 없습니다.

Regulation (EU) 2024/1183 (eIDAS 2)는 Article 8 수준을 계속 참조하며 European Digital Identity Wallets가 보증 수준 high로 제공될 것을 요구합니다. 이 페이지는 그것을 규제 맥락으로 인용합니다. NextPDF는 지갑 관련 기능 주장을 하지 않습니다.

특정 서명이 구조적 eIDAS 지향 정책을 충족하는지 여부는 별개의 문제이며, 검증 모듈이 답합니다. Validation을 참조하세요.

eIDAS LoA 클래스는 어떤 암호 연산도 수행하지 않습니다 — 해싱도, 서명 검증도, 무작위성도 없습니다. Enterprise FIPS 모드 정책은 암호 선택에 게이트를 걸므로, 이 모듈에는 게이트를 걸 것이 없습니다. FIPS 모드를 활성화해도 LoA 매핑이나 PII 가드 동작은 바뀌지 않습니다. 서명과 신뢰 목록의 암호 검증은 검증 및 보안 모듈이 관장하며, 거기에서 FIPS 모드 정책이 적용됩니다.

  • LoaMapping::loaForService() 는 전역적이고 결정적입니다. 모든 TspServiceLoaAssertion 을 산출하며, 이 메서드는 결코 던지지 않고 어떤 시계, 네트워크, 또는 전역 상태도 참조하지 않습니다.
  • 분류는 보수적입니다. 부재하거나 알 수 없거나 상충하는 증거는 수준을 낮추며, 명시적인 granted-CA/QC-with-QSCD 증거 외에는 아무것도 수준을 높이지 않습니다.
  • 사유 코드는 기계 판독 가능하고 안정적입니다: service_not_granted, service_not_qualified_ca, ca_qc_with_qscd, esig_or_eseal, qc_default, ca_qc_no_qscd_or_unspecified.
  • 수준 순서는 고정되어 있습니다: Low < Substantial < High, rank()meetsOrExceeds() 를 통해 노출됩니다.
  • CertPiiGuard 는 기본으로 편집하며 토큰화 의심 시 폐쇄 실패합니다. disclosePii: true 일 때는 모든 가드가 입력을 그대로 반환합니다.
  • 가드 출력은 동일한 입력에 대해 바이트 단위로 안정적입니다.

NextPDF Core는 PDF 서명을 암호적으로 검증하며 손상된 증거에 대해 폐쇄 실패합니다. Core에는 EU 신뢰 목록 모델도, LoaLevel 어휘도, LoA 매핑도, 감사 직렬화를 위한 eIDAS 계층 PII 가드도 없습니다. Core 단독으로는, 여러분이 유지하는 신뢰 데이터로부터 보증 분류를 직접 도출해야 하고, 감사 레코드가 프로세스를 떠나기 전에 자체 편집을 적용해야 합니다.

이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만을 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 테이블, 런북 파일명, 티켓 접두사는 범위 밖입니다.