Memutuskan bahwa sebuah tanda tangan PDF terkualifikasi di bawah eIDAS berarti menjawab pertanyaan yang tidak ada sangkut pindanya dengan kriptografi: apakah sertifikat diterbitkan oleh trust service yang didaftarkan sebuah negara anggota sebagai terkualifikasi, pada saat tanda tangan dibuat. Jawabannya berada di sebuah trusted list, dokumen XML yang dipublikasikan per wilayah, dan seluruh nilai dokumen itu bergantung pada keasliannya. Jadi komponen PDFium menolak melihat ke dalamnya sampai ada yang menjaminnya. TPdfEuropeanTrustedList.ParseAuthenticated menyerahkan byte mentah lengkap ke IPdfTrustedListAuthenticator yang disediakan caller sebelum ia mem-parse satu service pun, dan ia membuat snapshot hanya jika authenticator itu secara eksplisit lolos
Pengurutan itulah desainnya. Segala hal lain di fitur ini mengikuti darinya, termasuk bagian-bagian yang tampak merepotkan
Ter-parse bukan berarti tepercaya
Trusted list yang ter-parse bersih memberi tahu Anda XML-nya well formed. Ia tidak memberi tahu apa pun tentang siapa yang menulisnya. Karena list itulah tempat seluruh keputusan status terkualifikasi Anda berpijak, menerimanya karena ia ter-parse akan membuat keputusan itu tidak bermakna: penyerang yang bisa mengganti list bisa mendeklarasikan certificate authority miliknya sendiri sebagai terkualifikasi
Penalaran yang sama berlaku untuk caching, dan inilah jebakan yang layak dinamai. Cache snapshot menyimpan XML asli bersama digest SHA-256, dan mudah untuk memperlakukan digest yang cocok saat memuat sebagai bukti bahwa list itu asli. Tidak. Digest yang dihitung oleh proses yang sama yang menyimpan berkas, tanpa kunci yang terlibat, hanya memverifikasi bahwa byte tidak berubah sejak Anda menulisnya; jika list itu penipuan saat di-cache, digest mengonfirmasi bahwa itu list penipuan yang sama. Jadi memuat snapshot cache berjalan melalui authenticator yang sama seperti mem-parse yang baru. Integritas dan keaslian adalah properti yang berbeda dan hanya satu di antaranya membutuhkan kunci
uses
FPdfTrustedList;
type
TListAuthenticator = class(TInterfacedObject, IPdfTrustedListAuthenticator)
public
function Authenticate(const XmlData: TBytes;
out AuthenticationDetails: string): Boolean;
end;
function TListAuthenticator.Authenticate(const XmlData: TBytes;
out AuthenticationDetails: string): Boolean;
begin
// Kebijakan Anda berada di sini: verifikasi signature enveloped
// XMLDSIG terhadap sertifikat penanda list yang Anda pin di luar
// jalur, dan deskripsikan yang Anda periksa untuk audit trail
Result := VerifyEnvelopedXmlSignature(XmlData, FPinnedListSigner);
if Result then
AuthenticationDetails := 'XMLDSIG verified against pinned LOTL signer';
end;
var
List: TPdfEuropeanTrustedList;
Cache: TFileStream;
begin
List := TPdfEuropeanTrustedList.ParseAuthenticated(RawXml,
TListAuthenticator.Create, TPdfTrustedListOptions.Default);
// Snapshot hanya ada karena authenticator mengatakan ya
Cache := TFileStream.Create('tl-de.snapshot', fmCreate);
try
List.SaveCache(Cache);
finally
Cache.Free;
end;
end;
Validator tidak memiliki kebijakan jaringan
Validator PAdES tidak punya urusan memutuskan bagaimana mencapai list of trusted lists, apakah melewati proxy, seberapa sering mencoba ulang, atau apa yang dilakukan ketika sebuah wilayah tak terjangkau. Itu keputusan aplikasi dan deployment, dan di lingkungan yang diatur mereka sering diaudit. Jadi pembaruan datang melalui IPdfTrustedListSource, yang diserahkan URI dan batas byte serta mengembalikan byte
Yang ditegakkan komponen adalah invarian yang membuat sebuah pembaruan menjadi pembaruan alih-alih penggantian. Update mensyaratkan wilayah tidak berubah, nomor urut meningkat secara ketat, dan waktu terbit tidak mundur. Ketiga pemeriksaan itu mengalahkan serangan downgrade yang paling jelas: memutar ulang list yang lebih lama yang masih mencantumkan service yang sudah ditarik, atau menukar list wilayah lain yang service-nya tidak pernah Anda maksudkan untuk dipercaya
Batas parser, dan tanpa DTD sama sekali
TPdfTrustedListOptions membatasi ukuran XML, jumlah token, kedalaman nesting, jumlah service, jumlah sertifikat, dan ukuran sertifikat individual, dengan class function Default yang menyediakan nilai yang dapat dipakai. Trusted list adalah dokumen publikasi berukuran dapat diprediksi, sehingga batas murah untuk ditetapkan dan tidak ada list yang sah yang perlu melewatinya
Secara terpisah dan tanpa syarat, parser menolak deklarasi DTD dan entitas. Itu menutup baik denial of service ekspansi entitas maupun jalur pengungkapan entitas eksternal dalam satu penolakan, dan tidak berbiaya apa pun karena trusted list tidak memakai entitas. Parser XML apa pun yang terjangkau dari input tak tepercaya seharusnya dikonfigurasi seperti ini; bedanya di sini penolakan itu tidak dapat dikonfigurasi, sehingga tidak bisa dimatikan oleh perubahan opsi yang bermaksud baik
Status terkualifikasi dicatat di samping kepercayaan rantai, tidak dilebur ke dalamnya
Sisi evaluasi sengaja terpisah. TPadesTrustValidationOptions.QualifiedTrustEvaluator menerima IPdfQualifiedTrustEvaluator, yang diimplementasikan snapshot trusted list. Selama validasi evaluator menerima sertifikat leaf, rantai, dan waktu validasi, mencocokkan sertifikat service lewat perbandingan DER persis terhadap penandatangan dan rantai, mengombinasikan status service, identifier tipe service, dan URI qualifier pada titik waktu itu, dan mengembalikan record evaluasi
Hasilnya mendarat di dua tempat pada setiap tanda tangan: QualifiedTrustStatus sebagai status kasar, dan QualifiedTrust sebagai evaluasi lengkap dengan wilayah, nama provider, nama service, identifier tipe, status, dan waktu mulai status. Yang tidak dilakukannya adalah mengubah CertificateTrustStatus. Kepercayaan rantai sistem dan status terkualifikasi menjawab pertanyaan berbeda, dan laporan yang melebur keduanya tidak bisa membedakan "tepercaya tetapi tidak terkualifikasi" dari "terkualifikasi tetapi rantainya tidak tervalidasi", keduanya nyata dan keduanya butuh penanganan berbeda
var
Options: TPadesTrustValidationOptions;
Report: TPadesValidationResult;
I: Integer;
begin
Options := TPadesTrustValidationOptions.Default;
Options.CheckRevocation := True;
Options.QualifiedTrustEvaluator := List; // snapshot yang terautentikasi
Options.QualifiedValidationTime := SigningTime; // bukan Now
Report := Pdf.ValidatePadesTrust(Options);
for I := 0 to High(Report.Signatures) do
if Report.Signatures[I].QualifiedTrustStatus = pcsValid then
Writeln(Format('signature %d qualified by %s / %s (%s)',
[I, Report.Signatures[I].QualifiedTrust.Territory,
Report.Signatures[I].QualifiedTrust.ProviderName,
Report.Signatures[I].QualifiedTrust.ServiceName]))
else if Report.Signatures[I].QualifiedTrustStatus = pcsIndeterminate then
// Tidak ada service yang cocok, atau snapshot tidak bisa menjawab
// untuk waktu ini
Writeln(Format('signature %d: qualified status undetermined', [I]));
end;
Mengapa waktu validasi bukan sekarang
Karena kualifikasi adalah properti sebuah momen. Trust service bisa diberi status terkualifikasi, kemudian dicabut, dan kemudian dipulihkan lagi, dan setiap transisi itu membawa waktu mulai di list. Tanda tangan yang dibuat saat service terkualifikasi tetap terkualifikasi sesudahnya; tanda tangan yang dibuat sebelum pemberian tidak menjadi terkualifikasi secara retroaktif. Mengevaluasi terhadap waktu saat ini karenanya memberikan jawaban yang salah di kedua arah
List membawa apa yang dibutuhkan untuk ini: setiap record service punya waktu mulai status dan flag yang membedakan entri historis dari yang saat ini, dan evaluator mengombinasikannya terhadap waktu yang Anda berikan. Dalam praktik waktu itu datang dari timestamp tepercaya pada tanda tangan alih-alih waktu penandatanganan yang diklaim di CMS, dan itulah mengapa materi validasi jangka panjang penting bahkan untuk pertanyaan yang tampak seperti pencarian kebijakan; sisi timestamp dan DSS dibahas dalam artikel tanda tangan jangka panjang
Apa yang masih harus Anda bangun
Tiga hal, dan tidak satu pun termasuk pustaka PDF. Authenticator, artinya verifikasi XMLDSIG sesungguhnya terhadap sertifikat penanda list yang Anda peroleh melalui saluran yang Anda percayai. Kebijakan pengambilan, artinya bagaimana dan seberapa sering Anda menyegarkan, dan apa yang dilakukan aplikasi Anda ketika penyegaran gagal. Dan cakupan teritorial, artinya list mana yang Anda bawa sama sekali, yang merupakan keputusan bisnis tentang negara anggota mana mitra Anda menandatangani
Yang Anda dapat dari komponen adalah bagian yang mudah keliru secara halus: pengurutan autentikasi-sebelum-parse, parsing XML berbatas dan bebas entitas, invarian pembaruan monoton, pencocokan service DER persis, evaluasi status historis, dan hasil yang tetap terpisah dari kepercayaan rantai biasa. Jika masalah Anda yang mendesak lebih dasar, yaitu validator menolak tanda tangan yang Anda yakini baik, penyebab-penyebab lazimnya dikatalogkan dalam mengapa validator menolak tanda tangan PAdES, dan permukaan inspeksi tanda tangan dijelaskan dalam menginspeksi tanda tangan dan level PAdES. Kapabilitas komponen tercantum di halaman produk PDFium Delphi component