İçeriğe geç

PDF'yi PAdES B-B ile imzalama ve ardından PAdES B-T seviyesine genişletme

Bu tarifi Portable Document Format (PDF) Advanced Electronic Signatures (PAdES) B-B imzası üretmek için kullanın: imzalanmış öznitelikler (content-type, message-digest, signing-time) içeren bir Cryptographic Message Syntax (CMS) SignedData. Ardından bir RFC 3161 signature-time-stamp ekleyerek bu imzayı PAdES B-T seviyesine genişletin. B-T, B-B artı tek bir zaman damgasıdır; ayrı bir imza sınıfı değildir. Güven sınırı açıktır: bir imza üretmek, bir doğrulayıcının bunu geçerli saymasıyla aynı şey değildir.

U-1 uyarısı. NextPDF, PAdES B-T için bağımsız bir ETSI EN 319 142-1 sertifikasyon iddiasında bulunmaz. EN 319 142-1 doğrulama derlemine dahil değildir; B-T signature-time-stamp gerekliliği şunlara göre doğrulandı: ETSI EN 319 122-1 §5.3 ile birlikte RFC 3161, RFC 5652, RFC 5816 ve ISO 32000-2 §12.8. B-T profilinin desteklenmesi bir uygunluk veya yasal geçerlilik sertifikasyonu değildir; buna bağımsız bir doğrulayıcı karar verir.

B-LT ve B-LTA (Document Security Store (DSS) doğrulama materyali, arşivleme zaman damgası döngüsü) bu tarifin kapsamı dışındadır ve burada ele alınan Core/Pro imzalama yüzeyinin parçası değildir.

Terminal window
composer require nextpdf/core:^3

ext-openssl etkinleştirilmiş olmalıdır; çünkü CertificateInfo anahtarları OpenSSL üzerinden ayrıştırır. B-T için ayrıca erişilebilir bir RFC 3161 Time Stamping Authority (TSA) uç noktası ve bir PHP Standards Recommendation (PSR)-18 HTTP istemcisi gerekir.

Bir PAdES B-B imzası, imza sözlüğünün Contents girdisinde Distinguished Encoding Rules (DER) ile kodlanmış bir CMS SignedData saklar; Contents değeri, bayt aralığı özeti üzerinde dolgulanmış onaltılık bir dizgedir (ISO 32000-2 §12.8.1). Bu özet dosyayı kapsar ve imza değerinin kendisini hariç tutar (ISO 32000-2 §12.8.1).

PAdES B-T tam olarak bir RFC 3161 signature-time-stamp ekler. Zaman damgasının ileti özü, SignerInfo imza değeri sekizlilerinin karmasıdır ve herhangi bir Abstract Syntax Notation One (ASN.1) etiketi ya da uzunluk ön eki içermez (ETSI EN 319 122-1 §5.3; RFC 3161 Ek A). Belirteç, id-aa-timeStampToken imzalanmamış özniteliği olarak, nesne tanımlayıcısı (OID) 1.2.840.113549.1.9.16.2.14 (RFC 3161 Ek A) ile taşınır ve SignerInfo.unsignedAttrs [1] IMPLICIT içine yerleştirilir (RFC 5652 §5.3). İmzalanmamış öznitelikler imza tarafından korunmadığından (RFC 5652 §5.4), B-B imzalanmış özeti, /ByteRange ve B-B imza baytları değişmeden kalır — B-T yalnızca zaman damgasını ekler. TSA sertifikası ESSCertIDv2 ile tanımlanır (RFC 5816, RFC 3161 belgesini günceller).

U-1 uyarısı (B-T iddiasında yinelenmiştir). NextPDF, PAdES B-T için bağımsız bir ETSI EN 319 142-1 sertifikasyon iddiasında bulunmaz. EN 319 142-1 doğrulama derlemine dahil değildir; B-T signature-time-stamp gerekliliği ETSI EN 319 122-1 §5.3 ile birlikte RFC 3161, RFC 5652, RFC 5816 ve ISO 32000-2 §12.8 belgelerine göre doğrulandı. B-T profilinin desteklenmesi bir uygunluk veya yasal geçerlilik sertifikasyonu değildir; buna bağımsız bir doğrulayıcı karar verir.

SignatureLevel::PAdES_B_T Core’da kullanılabilir: SignatureLevel::PAdES_B_T->requiresTimestamp() true, ->isAvailableInEnvironment() true ve ->requiresDss() false döndürür — B-T beraberinde bir Document Security Store getirmez. B-T ≠ B-LT ≠ B-LTA: bir imza zaman damgası doğrulama materyali veya arşivleme zaman damgası eklemez; bunlar burada üretilmeyen ayrı, daha üst seviyelerdir.

Aşağıdaki şema, B-B ardından B-T akışını motorun kullandığı sırayla gösterir. ByteRange yalnızca dosyanın tamamı yazıldıktan sonra hesaplanır; böylece nihai uzaklıklar, karması alınan baytları değiştiremez. Ardından B-T, imzalanmamış bir öznitelik olarak bir RFC 3161 belirteci ekler ve B-B imzalanmış özetine dokunmaz.

RFC 3161 TSANextPDF DigitalSignerRFC 3161 TSANextPDF DigitalSignerReserve fixed-width /Contents slotand /ByteRange placeholderByteRange covers the whole fileexcluding the /Contents valuePAdES B-B completeB-T = B-B + 1 timestampB-B signed digest unchangedalt[level == PAdES B-T]Callersign — level B-B or B-T1Write the complete PDF incl. xref + EOF2Compute the two real ByteRange offsets3Hash the two concatenated segments4Build CMS SignedData with signed attrs5Hash the SignerInfo signature value — message imprint6TimeStampReq — message imprint + fresh nonce7TimeStampToken — signed, echoes imprint + nonce8Verify token — status, nonce, imprint, signature, time9Embed token in SignerInfo.unsignedAttrs10Signed PDF — /Contents = DER CMS SignedData11Caller
Diagram

Yapılandırma giriş noktası Document::setSignature(CertificateInfo $certInfo, SignatureLevel $level = SignatureLevel::PAdES_B_B, ?TsaClient $tsaClient = null) çağrısıdır. Bu çağrı, imzalama amacını belge üzerinde kaydeder. Core PAdES imzalama motoru (NextPDF\Security\Signature\DigitalSigner) kriptografik imzayı üretir. Entegrasyon paketi bu motoru çalıştırdığı ve çalıştırılabilir örnek onu doğrudan kullandığı için çıktı gerçek, ayrıştırılabilir bir CMS nesnesidir. SignatureLevel::PAdES_B_T, boş olmayan bir TsaClient gerektirir; bu olmadan bir B-T imzalayıcısı oluşturmak bir SignatureException fırlatır.

Üst düzey API — tek çağrı, imzalanmış çıktı

“Üst düzey API — tek çağrı, imzalanmış çıktı” başlıklı bölüm

En hızlı yol üst düzey API’dir: imzayı belge üzerinde yapılandırın, ardından serileştirin. Arka planda aynı Core PAdES motorunu (DigitalSigner) çalıştırır. Bu, aşağıdaki daha alt düzey adım adım kılavuzun üzerine eklenen ince bir kolaylık katmanıdır; ayrı bir kod yolu değildir.

<?php
declare(strict_types=1);
use NextPDF\Core\Document;
use NextPDF\Security\Signature\CertificateInfo;
use NextPDF\Security\Signature\SignatureLevel;
use NextPDF\Security\Timestamp\TsaClient;
$certInfo = CertificateInfo::fromPkcs12(
p12Path: __DIR__ . '/signer.p12',
password: 'p12-passphrase',
);
// PAdES B-B end to end: configure, then serialise.
$doc = Document::createStandalone();
$doc->addPage();
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'Signed end to end.', newLine: true);
$doc->setSignature(certInfo: $certInfo, level: SignatureLevel::PAdES_B_B);
$doc->save(__DIR__ . '/signed.pdf'); // or output() to stream, getPdfData() for bytes
// PAdES B-T: pass a TsaClient on the same call — one RFC 3161
// signature-time-stamp is added (see the TsaClient hardening notes below).
$doc->setSignature(
certInfo: $certInfo,
level: SignatureLevel::PAdES_B_T,
tsaClient: $tsa,
);
$doc->save(__DIR__ . '/signed-bt.pdf');

Tıpkı output() ve getPdfData() gibi, save() de /Contents girdisini, DER ile kodlanmış bir CMS SignedData olarak, SubFilter ETSI.CAdES.detached altında yazar (ISO 32000-2 §12.8, §12.7.5.5; RFC 5652). Çıktı CMS olarak doğrulanabilir: Bir CMS ayrıştırıcısının okuyabileceği iyi biçimlenmiş bir CMS SignedData nesnesidir. Bu, ETSI EN 319 142-1 taban profili uygunluğu veya yasal geçerlilik ile aynı şey değildir; bu belirlemeleri bağımsız bir doğrulayıcı yapar (yukarıdaki U-1 uyarısına bakın). B-T için üst düzey çağrı, kavramsal genel bakışta açıklanan tek RFC 3161 signature-time-stamp öğesini tam olarak ekler; TsaClient öğesini iletmek B-B ile tek farktır.

Aşağıdaki daha alt düzey DigitalSigner adım adım kılavuzunu, algoritma, bayt aralığı verisi veya SignatureResult üzerinde doğrudan denetim gerektiğinde kullanın.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Security\Signature\CertificateInfo;
use NextPDF\Security\Signature\DigitalSigner;
use NextPDF\Security\Signature\SignatureAlgorithm;
use NextPDF\Security\Signature\SignatureLevel;
$certInfo = CertificateInfo::fromPkcs12(
p12Path: __DIR__ . '/signer.p12',
password: 'p12-passphrase',
);
// PAdES B-B — a CMS SignedData, no timestamp.
$signer = new DigitalSigner(
certInfo: $certInfo,
level: SignatureLevel::PAdES_B_B,
algorithm: SignatureAlgorithm::Pkcs1v15,
);
$result = $signer->sign($byteRangeData);
echo $result->hasTimestamp() ? "B-T\n" : "B-B (no timestamp)\n";

Bu kendi başına çalışabilen program, cookbook test koşum ortamında çalışır. Şu örneği yansıtır: examples/36-sign-pades-b-b-and-b-t.php. Bir belge oluşturur, onu bir PAdES imzası için yapılandırır, ardından bir TSA istemcisiyle önce B-B, ardından B-T seviyesinde imzalar. Üretimde, TsaClient öğesini sağlamlaştırılmış bir PSR-18 istemcisi üzerinden gerçek bir RFC 3161 uç noktasına yönlendirin: TSA’nın SubjectPublicKeyInfo (SPKI) bilgisini sabitleyen ve Domain Name System (DNS) çözümlemesini güvenli yapan, güvenliğe duyarlı bir HTTP istemcisi. Bu programı çevrimdışı ve belirlenimci tutmak için depodaki test desteği olarak kullanılan sahte TSA istemcisini enjekte eder. Sahte TSA istemcisi, yapısal olarak geçerli bir RFC 3161 TimeStampResp döndürür.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Security\Signature\CertificateInfo;
use NextPDF\Security\Signature\DigitalSigner;
use NextPDF\Security\Signature\SignatureAlgorithm;
use NextPDF\Security\Signature\SignatureLevel;
use NextPDF\Security\Timestamp\TsaClient;
use NextPDF\Tests\Support\FakeTsaHttpClient;
// In your application, build CertificateInfo from your own signing material:
// CertificateInfo::fromPkcs12($p12Path, $passphrase) — a .p12/.pfx bundle
// CertificateInfo::fromFiles($certPem, $keyPem, $pass) — separate PEM files
// This program uses the repository RSA-2048 test fixtures so it is offline.
$certDir = __DIR__ . '/tests/Fixtures/Certificates';
$certPath = $certDir . '/test-rsa-2048-cert.pem';
$keyPath = $certDir . '/test-rsa-2048-key.pem';
if (!is_file($certPath) || !is_file($keyPath)) {
fwrite(STDERR, "Certificate fixtures absent. Run tests/Fixtures/Certificates/generate.sh\n");
exit(1);
}
$certInfo = new CertificateInfo(
certificate: (string) file_get_contents($certPath),
privateKey: (string) file_get_contents($keyPath),
);
// Build the document and record the signing intent on it. The ByteRange
// digest input is the document bytes with the /Contents placeholder
// excluded (ISO 32000-2 §12.8); getPdfData() yields the bytes to hash.
$doc = Document::createStandalone();
$doc->setTitle('Signed Invoice 2026-0042');
$doc->setAuthor('NextPDF Cookbook');
$doc->addPage();
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'This document is configured for a PAdES signature.', newLine: true);
$doc->setSignature(certInfo: $certInfo, level: SignatureLevel::PAdES_B_B);
$byteRangeData = $doc->getPdfData();
// --- PAdES B-B: a CMS SignedData, no timestamp ---
$bb = (new DigitalSigner(
certInfo: $certInfo,
level: SignatureLevel::PAdES_B_B,
algorithm: SignatureAlgorithm::Pkcs1v15,
))->sign($byteRangeData);
// --- PAdES B-T: B-B + one RFC 3161 signature-time-stamp ---
// In production, build the TsaClient with your TSA endpoint and a hardened
// PSR-18 client (use the security-aware HTTP client for SSRF/DNS pinning):
// $tsa = new TsaClient(
// tsaUrl: 'https://tsa.example.com/timestamp',
// httpClient: $hardenedPsr18Client,
// );
// Here the offline fake TSA client keeps the program network-free.
$tsa = new TsaClient(
tsaUrl: 'https://tsa.example.com/timestamp',
httpClient: new FakeTsaHttpClient(),
);
$bt = (new DigitalSigner(
certInfo: $certInfo,
tsaClient: $tsa,
level: SignatureLevel::PAdES_B_T,
algorithm: SignatureAlgorithm::Pkcs1v15,
))->sign($byteRangeData);
// B-T = B-B + a single timestamp token. The B-B signed digest is unchanged;
// $bt->timestampToken holds the DER-encoded RFC 3161 token.
printf("PAdES B-B CMS: %d bytes, timestamp=%s\n", $bb->getSize(), $bb->hasTimestamp() ? 'yes' : 'no');
printf(
"PAdES B-T CMS: %d bytes, timestamp=%s (%d-byte RFC 3161 token)\n",
$bt->getSize(),
$bt->hasTimestamp() ? 'yes' : 'no',
strlen($bt->timestampToken),
);
echo "B-T = B-B + one RFC 3161 signature-time-stamp (unsigned attribute).\n";
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script under the
// semantic profile (the signed CMS/timestamp bytes are inherently
// non-reproducible and are asserted by the PHPUnit harness, not a byte hash).
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
file_put_contents($out !== false && $out !== '' ? $out : __DIR__ . '/signed-invoice.pdf', $byteRangeData);

Beklenen STDOUT çıktısı (boyutlar sertifikaya ve TSA belirtecine göre değişir):

PAdES B-B CMS: <n> bytes, timestamp=no
PAdES B-T CMS: <n> bytes, timestamp=yes (<m>-byte RFC 3161 token)
B-T = B-B + one RFC 3161 signature-time-stamp (unsigned attribute).

U-1 uyarısı (B-T üretim iddiasında yan yana yer alır). NextPDF, PAdES B-T için bağımsız bir ETSI EN 319 142-1 sertifikasyon iddiasında bulunmaz. EN 319 142-1 doğrulama derlemine dahil değildir; B-T signature-time-stamp gerekliliği ETSI EN 319 122-1 §5.3 ile birlikte RFC 3161, RFC 5652, RFC 5816 ve ISO 32000-2 §12.8 belgelerine göre doğrulandı. B-T profilinin desteklenmesi bir uygunluk veya yasal geçerlilik sertifikasyonu değildir; buna bağımsız bir doğrulayıcı karar verir.

  • TSA istemcisi olmadan B-T. Bir B-T DigitalSigner nesnesini TsaClient olmadan oluşturmak bir SignatureException fırlatır (TSA, B-T için gereklidir). İmzalamadan önce TSA yapılandırmasını güvenceye alın.
  • TSA erişilebilirliği. B-T, imza başına canlı bir RFC 3161 gidiş-dönüşü gerçekleştirir. Bir TSA kesintisi, B-T imzasının üretilememesi anlamına gelir. İşlem hacminize uygun bir devre kesici ve bir TSA hizmet seviyesi anlaşması (SLA) kullanın; TsaClient bir devre kesiciyi kabul eder.
  • TSA HTTP istemcisini sağlamlaştırma. TsaClient öğesini, TSA’nın SubjectPublicKeyInfo (SPKI, RFC 7469 biçimi) bilgisini sabitleyen ve Domain Name System (DNS) çözümlemesini güvenli yapan bir PSR-18 istemcisine yönlendirin; TsaClient::extractPublicKeyPin() sabitleme değerini TSA sertifikasından türetir.
  • B-T, B-LT/B-LTA değildir. Bir imza zaman damgası doğrulama materyali (sertifikalar, Online Certificate Status Protocol (OCSP), sertifika iptal listesi (CRL)) veya arşivleme zaman damgası gömmez. Bunlar B-LT/B-LTA seviyeleridir ve bu tarif tarafından üretilmez.
  • Doğrusallaştırma çakışması. enableLinearization() ve yapılandırılmış bir imza birbirini dışlar — biri zaten ayarlandığında diğer çağrı bir InvalidConfigException fırlatır.
  • HSM anahtarları. Donanım güvenlik modülünde (HSM) tutulan bir anahtar için, CertificateInfo öğesini CertificateInfo::fromHsm() ile oluşturun; özel anahtar süreç belleğine asla girmez. PKCS#11 imzalayıcı sözleşmesi Core’dur; çalışan sağlayıcı Premium kapsamındadır.

Bir B-B imzası yerel bir CMS işlemidir. B-T, imza başına TSA’ya bir eşzamanlı RFC 3161 HTTP gidiş-dönüşü ekler. Toplu iş yüklerinde TSA gecikmesi ve hız sınırları için bütçe ayırın. Devre kesiciyle korunan bir TsaClient kullanın.

Üretilen bir imza, kendiliğinden güvenilir bir imza değildir. Bir imzanın doğrulanıp doğrulanmaması; sertifikaya, güven köküne ve doğrulayıcının ilkesine bağlıdır ve bunlar bu kitaplığın kapsamı dışındadır. Şifreleme gizliliği korur, bütünlüğü değil; imzalama bütünlüğü ve özgünlüğü korur, gizliliği değil. Anahtar muhafazasını birincil risk olarak ele alın: süreç belleğindeki bir yazılım anahtarı, yalnızca ana makine kadar güvenlidir.

İmzalama işlemi süreç içinde çalışır; belge baytları ve özel anahtar, yalnızca ileti özünü (imza değerinin bir karması) gönderen ve hiçbir zaman belge içeriği göndermeyen B-T TSA gidiş-dönüşü dışında ana makineyi terk etmez (RFC 3161 §2.4.1 MessageImprint). TSA’ya hiçbir belge metni veya kişisel olarak tanımlanabilir bilgi (PII) iletilmez. Yargı bölgenizin veri yerleşimi ilkesiyle eşleşen bir TSA seçin.

DigitalSigner, isteğe bağlı bir PSR-3 günlükleyici kabul eder. Algoritmayı ve seviyeyi günlüğe kaydeder; anahtar materyalini veya imza baytlarını kaydetmez. password parametreleri — CertificateInfo ve TsaClient üzerindekiler — #[SensitiveParameter] ile işaretlenmiştir; böylece parolalar yığın izlerinden çıkarılır. SignatureResult::$cmsSignedData veya $timestampToken öğesini günlüğe yazmayın.

Değerlendirilenler: imzalamadan sonra kurcalanmış girdi (bayt aralığı özetiyle saptanır), anahtar ifşası (anahtar muhafazası entegratörün sorumluluğu olduğundan kitaplık kapsamı dışında), TSA kimliğine bürünme (TSA HTTP istemcisinde SPKI sabitlemesiyle azaltılır) ve seviyeler arasında düşürme (seviye enum’u açıktır; motor B-T seviyesini sessizce B-B seviyesine düşürmez). İleri sürülmeyenler: güvenlik açıklarının bulunmadığı veya elde edilen herhangi bir imzanın yasal olarak geçerli olduğu.

İmzalama temel öğeleri OpenSSL tarafından sağlanır. Federal Information Processing Standards (FIPS) ile doğrulanmış bir OpenSSL yapısında, RSA/ECDSA ve SHA-256 işlemleri FIPS sağlayıcısı üzerinden çalışır; NextPDF kendisi FIPS doğrulamasını ileri sürmez. CryptoCapabilities ana makinede kullanılabilir temel öğeleri bildirir; dağıtımınızdaki OpenSSL sağlayıcı zincirini doğrulayın.

İfadeBelirtimMaddereference_id
Bayt aralığı özeti dosyayı kapsar ve imza değerini hariç tutar.ISO 32000-2§12.8.1
Contents DER CMS SignedData tutar; bir belge zaman damgasında Contents bir TimeStampToken tutar.ISO 32000-2§12.8.1
Contents, bayt aralığı özeti üzerinde dolgulanmış onaltılık bir dizgedir.ISO 32000-2§12.8.1
signature-time-stamp özü, SignerInfo imza değeri sekizlilerinin karmasıdır (ASN.1 tag/length yok).ETSI EN 319 122-1§5.3
signature-time-stamp değeri bir SignatureTimeStampToken’dir.ETSI EN 319 122-1§6
MessageImprint ::= SEQUENCE { hashAlgorithm, hashedMessage }.RFC 3161§2.4.1
İmza zaman damgası özü, SignerInfo imza alanının karmasıdır; SignatureTimeStampToken ::= TimeStampToken.RFC 3161Ek. A
id-aa-timeStampToken OID değeri 1.2.840.113549.1.9.16.2.14 şeklindedir.RFC 3161Ek. A
SignerInfo unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL taşır.RFC 5652§5.3
İmzalanmamış öznitelikler imza tarafından korunmaz; B-B imzalanmış özeti değişmeden kalır.RFC 5652§5.4
RFC 5816, RFC 3161 belgesini günceller; ESSCertIDv2, TSA sertifikasını SHA-1 olmadan tanımlar.RFC 5816§1

Bu tarif, NextPDF’in bir B-B ve bir B-T imzasını nasıl ürettiğini açıklar. Elde edilen herhangi bir imzanın yasal olarak geçerli olduğunu veya PAdES uygunluğunun sağlandığını ileri sürmez; bu belirlemeleri bağımsız bir doğrulayıcı yapar.

PAdES B-LT ve B-LTA (DSS doğrulama materyali ve arşivleme zaman damgası döngüsü) ile PKCS#11 HSM anahtar muhafazası, Pro ve Enterprise sürümlerinde sunulur. Bu tarif yalnızca B-B ve B-T seviyelerini kapsar; daha üst seviyeler ayrı yeteneklerdir, ayrıca doğrulanır ve burada kapsam dışındadır.