Tek bir PAdES imzasını doğrulamak, üç bağımsız şeyi kontrol etmek anlamına gelir ve bir görüntüleyicideki yeşil onay işareti size yalnızca üçüncüsü hakkında bir şey söyler. Birincisi, /ByteRange dizisi doğru baytları kapsamak zorundadır: adlandırdığı aralıklar, imzalı hiçbir bayt dışarıda kalmadan, CMS özetinin alındığı tam girdiyi yeniden kurmalıdır. İkincisi, CMS'nin içindeki sertifika, güvendiğiniz bir köke zincirlenmek ve PAdES'in gerektirdiği imzalı imzalama-sertifikası özniteliğini taşımak zorundadır. Üçüncüsü, profil bir zaman damgası iddia ediyorsa, bir RFC 3161 tokeni, sertifika süresi dolmadan önceki bir zaman noktasına imza değerini bağlamak zorundadır. Acrobat, üçünü de tek bir simgeye sıkıştırır; bir uygunluk denetleyicisi bunları ayrı tutar ve bu dosyaları üreten kod da öyle yapmalıdır. losLab PDF Library (PDF Library for Delphi), bunun imzalama tarafını, zaman damgası yeniden gömme işlemini ve güvenmeden önce bir ByteRange'i incelemenizi sağlayan denetim çağrılarını size verir
Bir ayrım, neredeyse her ilk PAdES uygulamasını tökezletir, bu yüzden herhangi bir koddan önce belirtmeye değer. /SubFilter /adbe.pkcs7.detached ile yazılan bir imza, Acrobat'ın geçerli olarak bildireceği tamamen sağlam bir ISO 32000-1 §12.8 imzasıdır. Ama bir PAdES imzası değildir, çünkü ETSI EN 319 142-1 her temel düzeyde ETSI.CAdES.detached'i gerektirir. Bir eIDAS uygunluk denetleyicisi, kriptografi aynı olsa bile birincisini reddeder ve ikincisini kabul eder. Profil, belgenin kendisi hakkında yaptığı bir iddiadır ve o iddiayı doğru yapmak PDF Library for Delphi'ta tek bir çağrıdır
Bir PDF imzasını PAdES imzasına dönüştüren nedir
ETSI EN 319 142-1, CMS biçimi üzerine yığılmış dört temel düzey tanımlar. PAdES-B-B giriş noktasıdır: ETSI.CAdES.detached SubFilter'ı ve imzalı bir imzalama-sertifikası özniteliği taşıyan, bir PDF imza alanındaki bir CAdES imzası. PAdES-B-T, imza değerinin üzerine bir RFC 3161 zaman damgası ekler ve imzanın, kimsenin geri tarihlendiremeyeceği bir zaman noktasından önce var olduğunu kanıtlar. PAdES-B-LT, doğrulama için gereken sertifikaları, CRL'leri ve OCSP yanıtlarını bir Belge Güvenlik Deposu'na gömer; böylece dosya, veren CA altyapısını emekliye ayırdıktan sonra bile doğrulanabilir kalır. PAdES-B-LTA, algoritmalar zayıfladıkça birikmiş kanıtı yeniden koruyan bir belge zaman damgasıyla yığını tepeler
PDF Library for Delphi, bu kavramları kendi imzalama-süreci API'sine eşler. Profil işaretleyicisi SetSignProcessCustomSubFilter'dır. Politikanız bir taahhüt-türü göstergesine ihtiyaç duyuyorsa (köken kanıtı, onay kanıtı veya 1'den 6'ya kadar numaralandırılmış diğer ETSI tanımlayıcılarından biri), bu SetSignProcessCommitmentType üzerinden geçer. Açık bir imza politikası, politika OID'sini ve özetini alan SetSignProcessSignaturePolicy ile eklenir. Bir varsayılan dikkati hak eder: özet algoritması otomatikte bırakıldığında, kütüphane ETSI ve adbe.pkcs7.detached imzaları için SHA-256'yı seçer ve yalnızca eski adbe.pkcs7.sha1 yolunda SHA-1'e düşer. Yine de onu açıkça ayarlayın. Denetçiler hangi özeti kullandığınızı sorar ve koddaki açık bir değer, açıklamak için kılavuzu okumaya gitmeniz gereken bir varsayılandan savunması daha kolaydır
Temel düzey imzayı üretmek
Düz API, imzalamayı tek seferlik bir durum makinesi olarak sürer: kaynak dosya üzerinde bir süreç açın, onu yapılandırın, bir çıktı dosyasına bitirin, sonuç kodunu okuyun. Aşağıdaki dizi, SHA-256 ile bir PAdES-B-B imzası üretir. En çok önem taşıyan satırın imzanın kendisiyle hiçbir ilgisi yoktur. O, bilinçli olarak abartılı büyütülmüş /Contents ayırmasıdır, çünkü bu imzaya bir gün bir zaman damgası eklemeniz gerekirse sonradan değiştiremeyeceğiniz tek şeydir
var
Pdf: TPDFlib;
SignId: Integer;
begin
Pdf := TPDFlib.Create;
try
SignId := Pdf.NewSignProcessFromFile('invoice.pdf', '');
if SignId = 0 then
raise Exception.Create('cannot open source PDF');
Pdf.SetSignProcessField(SignId, 'Sig1');
Pdf.SetSignProcessPFXFromFile(SignId, 'company.pfx', PfxPassword);
Pdf.SetSignProcessInfo(SignId, 'Approved', 'Vienna', 'billing@example.com');
Pdf.SetSignProcessCustomSubFilter(SignId, 'ETSI.CAdES.detached');
Pdf.SetSignProcessDigestAlgorithm(SignId, 2); // SHA-256
Pdf.SetSignProcessReserveContentsBytes(SignId, 8192); // daha sonra bir zaman damgası için yer
Pdf.EndSignProcessToFile(SignId, 'invoice-signed.pdf');
if Pdf.GetSignProcessResult(SignId) <> 1 then
raise Exception.CreateFmt('signing failed, code %d',
[Pdf.GetSignProcessResult(SignId)]);
Pdf.ReleaseSignProcess(SignId);
finally
Pdf.Free;
end;
end;
NewSignProcessFromFile, kaynak hiç açılamadığında 0 döndürür. Bundan sonra, GetSignProcessResult, üretimde gerçekten oluşan başarısızlık modlarını ayırır: 4 yanlış bir PDF parolasını, 7 yanlış bir PFX parolasını, 9 özel anahtarı olmayan bir sertifika dosyasını, 10 yazılamayan bir çıktı yolunu, 11 imza baytları uygulanırken oluşan bir hatayı gösterir. Sayısal kodu girdi dosya adının yanına günlüklemek, belirsiz bir destek talebini bir dakikalık bir teşhise dönüştürür
Kütüphanenin sizin için getirmeyeceği RFC 3161 zaman damgasını eklemek
PDF Library for Delphi hiçbir TSA istemcisi göndermez ve bu bir eksiklik değil, bilinçli bir sınırdır. Kütüphane, zaman damgası otoritesinin karşı imzalaması gereken özeti hesaplar ve sonrasında genişletilmiş CMS'yi yeniden gömer; aradaki HTTP alışverişi ve CMS ameliyatı çağırana aittir. Bu ayrımın sıkı bir teknik nedeni vardır. İmzasız öznitelikleri sözde ekleyen Windows CryptoAPI kontrolü CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, PAdES'in kullandığı ayrık SignedData düzeninde CRYPT_E_INVALID_INDEX ile başarısız olur. Bu yüzden geliştirilmiş CMS'nin kendi kontrolünüzdeki bir CMS kodlayıcısından gelmesi gerekir. Hiçbir kütüphane, tokeni tek bir sistem çağrısıyla sessizce içine katlayamaz ve öyle iddia eden herhangi biri, ameliyatı sizin göremediğiniz bir yerde yapıyordur
var
Pdf: TPDFlib;
StsId: Integer;
HashHex, TstDer, TsAttr, AugmentedCms: AnsiString;
begin
Pdf := TPDFlib.Create;
try
StsId := Pdf.NewPAdESSignatureTimeStampProcessFromFile('invoice-signed.pdf', '');
Pdf.SetPAdESSignatureTimeStampField(StsId, 'Sig1');
Pdf.SetPAdESSignatureTimeStampDigestAlgorithm(StsId, 2);
HashHex := Pdf.GetPAdESSignatureValueHashHex(StsId);
// aşağıdaki iki çağrı da uygulama kodudur: TSA'nıza bir HTTP POST,
// ve tokeni imzasız bir öznitelik olarak ekleyen bir CMS yeniden kodlaması
TstDer := RequestTimeStampToken(HashHex);
TsAttr := Pdf.BuildPAdESSignatureTimeStampAttribute(TstDer);
AugmentedCms := AttachUnsignedAttribute(Pdf.GetPAdESSignatureCMSBytes(StsId), TsAttr);
Pdf.SetPAdESSignatureCMSBytes(StsId, AugmentedCms);
Pdf.EndPAdESSignatureTimeStampProcessToFile(StsId, 'invoice-bt.pdf');
if Pdf.GetPAdESSignatureTimeStampProcessResult(StsId) <> 1 then
raise Exception.Create('timestamp embedding failed');
Pdf.ReleasePAdESSignatureTimeStampProcess(StsId);
finally
Pdf.Free;
end;
end;
Buradaki sonuç kodlarına dikkat edin: 12, adlandırılan imza alanının var olmadığını, 11 mevcut CMS'nin ayrıştırılamadığını ve 13 genişletilmiş CMS'nin artık ayrılmış /Contents yer tutucusuna sığmadığını gösterir. Acı veren kod 13'tür, çünkü tek çözüm yeniden imzalamaktır: sertifika zinciriyle birlikte tipik bir zaman damgası tokeni 4 ila 6 KB tutar ve B-B adımı sırasında yapılan 8192 baytlık ayırma, tam olarak bu adımın inecek yeri olsun diye vardır
Doğrulama, sertifika zincirinde değil ByteRange'de başlar
Bir görüntüleyicideki yeşil onay işareti, dosya hakkında yapısal bir hüküm değil, o makinenin sertifika deposuna karşı bir güven kararıdır. Programlı doğrulama daha aşağıdan, artımlı güncellemelerin incelttiği soruyla başlamalıdır: her imza gerçekte hangi baytları kapsıyor? Burada tartışılan her geliştirme, ister ikinci bir imza, ister bir DSS sözlüğü, ister bir belge zaman damgası olsun, artımlı güncelleme üzerinden gelir ve her güncelleme, önceki imzanın /ByteRange'inin dışında baytlar ekler. Bu eklenen baytlar meşrudur. Bir doğrulayıcı yine de bunları belgenin değişiklik politikasına karşı sınıflandırmak zorundadır ve o politikanın yaşadığı alan başına DocMDP düzeyi GetSignatureDocMDPLevelByName ile okunabilir
var
Doc: TPDFlibSignDoc;
Names: TStringList;
I: Integer;
B0, B1, B2, B3, FileSize: Int64;
begin
FileSize := TFile.GetSize('invoice-bt.pdf'); // Open'dan önce: SignDoc bir paylaşım kilidi tutar
Doc := TPDFlibSignDoc.Create;
try
if not Doc.Open('invoice-bt.pdf', '', False) then
raise Exception.Create('cannot open for audit');
Names := TStringList.Create;
try
Doc.GetSignatureFieldNames(Names);
for I := 0 to Names.Count - 1 do
if Doc.GetSignatureValueObjNum(Names[I]) > 0 then // >0 gerçekten imzalandığı anlamına gelir
begin
B0 := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 11)));
B1 := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 12)));
B2 := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 13)));
B3 := StrToInt64(string(Doc.GetSignatureValueByName(Names[I], 14)));
if (B0 = 0) and (B2 + B3 = FileSize) then
Writeln(Names[I], ': covers the file to EOF')
else
Writeln(Names[I], ': earlier revision, or unexpected ByteRange layout');
end;
finally
Names.Free;
end;
Doc.Close;
finally
Doc.Free;
end;
end;
Bu denetim yolunda iki tuzak yaşar. TPDFlibSignDoc.Open, dosyayı özel bir paylaşım kilidiyle tutar; bu yüzden CMS doğrulaması için ham dosya baytlarını da özetlemek isteyen bir doğrulayıcı, dosyayı denetim için açmadan önce belleğe okumak zorundadır. Bu sırayı tersine çevirirseniz okuma, kendi koyduğunuz bir kilitte başarısız olur. İkinci tuzak yüksek sesli değil sessizdir: düz-API karşılığı GetSignProcessByteRange, alttaki ofsetler Int64 iken bir Integer döndürür; bu yüzden 2 GB'ın ötesinde düz çağrı şikayet etmeden kırpar, bu örneğin ofsetleri bunun yerine denetim sınıfı üzerinden çekmesinin nedeni de budur. Adlandırılmaya değer bir eksiklik daha var. Düz katmanın hiçbir VerifySignature sarmalayıcısı yoktur. Kriptografik hükümler, vsValid, vsInvalid veya vsUnknown döndüren sınıf düzeyindeki TPDFlibSignatureVerifier'dan veya uyumluluk politikanızın zaten güvendiği harici bir doğrulayıcıdan gelir
Uzun vadeli doğrulama: DSS, VRI ve belge zaman damgası
PAdES-B-LT, geçersiz kılma altyapısı ölümlü olduğu için vardır. ETSI EN 319 142-1 §5.4.2.2, Belge Güvenlik Deposu'nu belirtir: sertifikaları, CRL'leri ve OCSP yanıtlarını taşıyan, isteğe bağlı olarak her imzanın /Contents'inin özetiyle anahtarlanmış VRI girdileri üzerinden imza başına indekslenen, belge düzeyinde bir sözlük. PDF Library for Delphi akışı, zaman damgası tasarımını yansıtır. NewPAdESDSSProcessFromFile süreci açar; AddPAdESDSSCertificate, AddPAdESDSSCRL ve AddPAdESDSSOCSP DER blob'ları kabul eder; AddPAdESDSSVRI seçili malzemeyi bir imzaya bağlar; EndPAdESDSSProcessToFile her şeyi bir artımlı güncelleme olarak yazar. Zor kısım sizin tarafınızda kalır. Geçersiz kılma malzemesini getirmek ve onun gömmeye değecek kadar taze olup olmadığına karar vermek, çağıranın işidir. Kütüphane, sözlüklerin yapısal olarak uygun olduğunu garanti eder; OCSP yanıtlayıcınızın doğruyu söylediğini garanti edemez
Arşivsel uç nokta B-LTA, bir belge zaman damgası ekler: ayrılmış bir imza uzunluğuyla SetSignProcessDocTimeStamp üzerinden üretilen, türü Sig değil DocTimeStamp olan ayrı bir imza alanı. Bu, B-T adımındaki imza zaman damgasının yerini almaz. İmza zaman damgası, belirli bir imzanın ne zaman var olduğunu kanıtlar; belge zaman damgası ise DSS kanıtı dahil olmak üzere tüm dosyayı korur ve algoritmalar zayıfladıkça uzun vadeli bir arşivin birkaç yılda bir yenilediği unsurdur. Olgun bir arşivsel profil ikisini de taşır. Bu yapılardan öncesine ait okuyucular için TPDFlibSignDoc.EnsurePAdESExtensions, dosyanın ETSI tanımlı özellikler kullandığını duyurarak ESIC geliştirici uzantısını belge kataloğuna kaydeder
Tüm bunlara bir tepkinin önüne geçmeye değer, çünkü bir hata gibi görünür ama değildir. Bir görüntüleyici, PAdES yapısı tamamen doğru olan bir dosyada sık sık "geçerlilik bilinmiyor" bildirir. Güven ve yapı bağımsız eksenlerdir. Görüntüleyici, ByteRange denetimi ve CMS doğrulaması ikisi de geçse bile, imzalayanı o makinede güvendiği bir köke zincirleyemez; bu, özel CA'lar ve test sertifikalarıyla rutindir. Çözüm, kök sertifikayı düzgün dağıtmak veya gerçek hedef nitelikli eIDAS statüsüyse AB güvenilir listelerine karşı değerlendirmektir, imzalama koduna dokunmak değil
Denetim tarafı perspektifi için, yani bir belge kümesi genelinde imza alanlarını numaralandırmak, ByteRange düzenlerini dökmek ve DocMDP düzeylerini toplu okumak için, uyumluluk ve imzalama çalışma tezgâhı konulu yoldaş yazıya bakın. Aynı zamanda arşivsel politikayı da karşılamak zorunda olan imzalı belgeler, Delphi'de PDF/A ve PDF/UA ön kontrolü makalesinde açıklanan iş akışına aittir. Tam API belgeleri ve değerlendirme indirmeleri, losLab PDF Library for Delphi ürün sayfasındadır