HotPDF, ISO/TS 32004 PDF MAC doğrulamasını dosya başına değil revizyon başına yapar. THotPDF.ValidatePDFMACChain, zincir çapasından ileriye doğru her artımlı güncellemeyi gezer ve her MAC öğesini, o revizyonun kendi startxref ve %%EOF işaretinde biten salt okunur bir önek akışına karşı doğrular. En yeni revizyondaki tek bir geçerli MAC, altındaki revizyonlar hakkında hiçbir şey kanıtlamaz
Bütün bunları motive eden senaryo şu. Üzerinde PDF MAC bulunan AES-256 şifreli bir PDF dağıtıyorsunuz. Birisi dosyayı bir hex düzenleyicide açıyor, ilk MAC korumalı revizyonun içinde bir baytı çeviriyor, ardından kendi mükemmel geçerli MAC değerini taşıyan yepyeni bir revizyon ekliyor. Her görüntüleyici dosyayı şikayetsiz açar ve geçerli bayt aralığını etkin kuyruktaki MAC ile karşılaştıran saf bir denetçi başarı bildirir; çünkü o MAC, kapsadığı baytlar için gerçekten doğrudur. Hasar iki revizyon aşağıda, kimsenin yeniden denetlemediği bir bölgede durur
Geçerli bir üst düzey MAC dosyanın sağlam olduğunu neden kanıtlamaz?
Çünkü PDF MAC bir belgeyi değil bir öneki kapsar. Artımlı güncelleme biçimin birinci sınıf bir parçasıdır: her kaydetme yeni bir gövde, yeni bir çapraz başvuru bölümü ve yeni bir kuyruk eklerken eski baytlar tam olarak oldukları yerde kalır. ISO/TS 32004 bu modelin üzerine biner; bu yüzden her revizyon, dosyayı o anki haliyle doğrulayan kendi /AuthCode sözlüğünü taşır ve yalnızca en yeniyi doğrulamak her önceki revizyonu incelenmemiş bırakır. HotPDF bu yüzden iki soruyu iki çağrı olarak sunar ve aralarındaki fark bu makalenin tamamının özüdür. ValidatePDFMAC «geçerli revizyon özgün mü» sorusunu yanıtlar ve bir THPDFPDFMACValidationInfo kaydı doldurur; ValidatePDFMACChain «bu dosyadaki MAC korumalı her revizyon özgün mü» sorusunu yanıtlar ve THPDFPDFMACChainValidationInfo kaydını revizyon başına bir dizi artı makine tarafından okunabilir bir hata nedeniyle doldurur. Yukarıdaki değiştirilip yeniden MAC eklenmiş dosyada ilk çağrı True döndürür, ikinci çağrı ise revizyon dizini 1 için False döndürür
var
Pdf: THotPDF;
Chain: THPDFPDFMACChainValidationInfo;
I: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if not Pdf.ValidatePDFMACChain('incoming.pdf', 'user', Chain) then
begin
// Hata şunlardan biridir: pmcfRevisionBoundary, pmcfNoPDFMAC,
// pmcfRequiredRevisionMissing, pmcfRevisionInvalid,
// pmcfKDFSaltChanged, pmcfDigestDowngrade, pmcfPermissionDowngrade
Writeln('chain rejected: ', Chain.Message);
Writeln('revision ', Chain.FailureRevisionIndex,
' at xref offset ', Chain.FailureXRefOffset);
Exit;
end;
for I := 0 to High(Chain.Revisions) do
Writeln(I, ' len=', Chain.Revisions[I].RevisionLength,
' mac=', Chain.Revisions[I].HasPDFMAC,
' perms=', Chain.Revisions[I].PermissionsAuthenticated);
finally
Pdf.Free;
end;
end;
Her MAC kendi önek akışında doğrulanır, asla son dosya uzunluğunda değil
Bu alandaki en pahalı hata, eski bir revizyonu yeniden karma yaparken üst sınır olarak son dosya boyutunu kullanmaktır; bu, sondaki baytları en yeni hariç her özetin içine katar ve sağlam bir dosyada kurcalama bildirir. HotPDF bunun yerine her revizyon için o revizyonun kendi startxref değerinde ve ardından %%EOF işaretinde biten sınırlı salt okunur bir akışı yeniden kurar ve yalnızca onu karma yapar. Sınırı bulmak göründüğünden daha zahmetlidir: %%EOF değişmezi bir içerik akışının ya da dizginin içinde görünebilir; bu yüzden bir aday ancak hemen önceki startxref değeri, doğrulanan bölümün çapraz başvuru ofsetine eşit bir sayıya ayrıştığında ve aralarında boşluktan başka bir şey olmadığında kabul edilir. Revizyon sonra işaretin ardından tam olarak bir satır sonu dizisini — tek CR, tek LF ya da bir CRLF çifti — içerir ve fazlasını içermez. Bu son kural pratikte ısırır; çünkü iki revizyon arasına fazladan boş satır yayan bir yazıcı, sonraki revizyona ait baytlar üretmiştir ve tüm sondaki boşluğu öncekine yutmak her iki özeti de sessizce değiştirir. Bölüm numaralandırması aynı disiplini izler: HotPDF çapraz başvuru bölümlerini eskiden yeniye tam olarak bir kez gezer; free, direct ve object-stream girdilerini yeniden oynatır, böylece sonraki bölümler önceki durumun üzerine yazar ki bu, aktif xref ayrıştırıcısının uyguladığı ilk görülen kazanır anlambiliminin tersidir
Zincir nereye çapalanır ve ne onu kırar?
Geçerli bir /AuthCode taşıyan ilk revizyon çapadır ve FirstMACRevisionIndex korumanın nerede başladığını bildirir; öncesindeki her şey yapı gereği korumasızdır ki bu normaldir. Sonrasındaki her şey MAC korumalı olmalıdır; bu yüzden MAC korumalı bir dosyaya tek bir düz artımlı güncelleme eklemek pmcfRequiredRevisionMissing ve suçlu revizyon diziniyle başarısız olur. Bir boşluğa göz yummak, saldırganın yalnızca bir kez daha kaydederek korumayı sıyırmasına izin verirdi. Zincir boyunca üç ek değişmez geçerlidir; her birinin kendi hata kodu vardır
pmcfKDFSaltChanged—/KDFSaltdeğeri çapadan itibaren sabit kalmalıdır; çünkü dönen bir salt, sahtecinin anahtarları kendi seçtiği parametrelerle yeniden türetmesine izin verirdipmcfDigestDowngrade— özet gücü hemen önceki revizyon yerine doğrulanmış son MAC ile karşılaştırılır; böylece Modern profili altında SHA-384 ile başlayan bir zincir sessizce SHA-256 ile devam edemezpmcfPermissionDowngrade— bir revizyon, önceki bir revizyonun kimliğini doğruladığı PDF MAC gereksinimini temizleyemez
İçselleştirmeye değer sonuç, geçmiş MAC değerlerinin artık etkin kuyruk olmadıktan sonra bile bağımsız olarak doğrulanmasıdır. Açılıştaki eski revizyonu düzenle, sonra yeni MAC ekle saldırısının ayakta kalamaması bundandır: en yeni MAC kendi başına doğrulanır, ValidatePDFMAC memnundur ve zincir yine de revizyon 1 üzerine pmcfRevisionInvalid ile iner
İmza sıralaması: önce kuyruk anahtarları, en son signatureDigest
MAC tek başına durmak yerine bir CMS imzasına bağlandığında yazım sırası üslup sorusu olmaktan çıkar. HotPDF, imza /ByteRange değeri hesaplanmadan önce /AuthCode, /KDFSalt, ISO 32004 geliştirici uzantısı ve /SigObjRef öğelerinin aynı revizyona yazılmasını ister; herhangi birini sonra eklerseniz o baytlar imzanın kapsadığı aralığın dışına düşer ve imzası doğrulanan ama MAC bağlaması imzasız bir dosya üretirsiniz. İki özet sonra ters yönde çalışır; ilk bakışta döngüsel görünür ama değildir. PDF MAC signatureDigest öğesi, CMS SignerInfo.signature OCTET STRING öğesinin ham içerik sekizlilerini bağlar — tüm CMS DER öğesini değil, imzalı öznitelikleri de değil — bu yüzden ham imza değeri var olduktan sonra kurulur ve id-attr-pdfMacData imzasız özniteliği olarak enjekte edilir. /Contents imza ByteRange dışında tutulduğundan ve imzasız öznitelikler imza hesaplamasına asla girmediğinden imzala, MAC kur, CMS sar dizisi kriptografik döngü olmadan temizce kapanır. İki sonuç çıkar: /ByteRange bekçisi ve /Contents yer tutucusu şifreli dosyada bile düz metin kalmalı ve nesne akışlarının dışında durmalıdır, yoksa sabit genişlikli yamalıcı onları bulamaz; MAC özeti de SHA-256 olduğunda imzalama özeti doğrudan yeniden kullanılır, aksi halde iki özet bağlamı da çıktı akışı üzerinde tek geçişte güncellenir
var
Pdf: THotPDF;
Options: THPDFPDFMACOptions;
Info: THPDFPDFMACValidationInfo;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.AutoLaunch := False;
Pdf.FileName := 'unsigned.pdf';
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aesgcm;
Pdf.OwnerPassword := 'owner';
Pdf.UserPassword := 'user';
Pdf.ProtectOptions := [prPrint, prExtractContent];
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 12);
Pdf.CurrentPage.AddSignedSignatureField('Approval',
Rect(72, 120, 280, 160), 16384);
Pdf.EndDoc;
Options := THPDFPDFMACOptions.Modern; // SHA-384 belge özeti
if THotPDF.SignPDFWithPFXAndAttachedPDFMAC('unsigned.pdf',
'signed.pdf', 'signer.pfx', 'pfx-secret', 'user', Options) then
if Pdf.ValidatePDFMAC('signed.pdf', 'user', Options, Info) then
begin
// Location = pmlAttachedToSignature ve iki özet
// ayrı ayrı raporlanır
Writeln('signature object : ', Info.SignatureObjectNumber);
Writeln('signature digest : ', Info.SignatureDigestMatched);
Writeln('full file coverage: ', Info.FullFileCoverage);
Writeln('perms authentic : ', Info.PermissionsAuthenticated);
end;
finally
Pdf.Free;
end;
end;
Doğrulama aynı yolu öbür uçtan geri izler: o an etkin klasik çapraz başvuru kuyruğundan doğrudan /AuthCode öğesini oku, nesil duyarlı dolaylı /SigObjRef öğesini izle, tek imza alanının /V öğesini bağladığını doğrula ve belge özeti hatasını imza özeti hatasından ayrı raporla. Bunlar farklı tanılardır ve tek bir boolean içinde birleştirmek, sayfa içeriğinin mi yoksa imza değerinin mi değiştirildiğini söyleyen tek bilgiyi atar. Zaten CMS işi yapıyorsanız bu, PAdES imzalama makalesi ve yüklenen belgelerde imza doğrulama kılavuzu ile yan yana durur
/P öğesine asla güvenmeyin: önce 16 baytlık /Perms şifresini çözün
ISO/TS 32004, «bu belge PDF MAC gerektirir» sinyalini 13. izin biti üzerinden verir ve onu okumanın bariz yolu yanlış olandır; çünkü şifreleme sözlüğündeki /P tamsayısı düz metindir ve kimliği doğrulanmamıştır — herkes o biti bir metin düzenleyicide çevirip gereksinimi düşürebilir. ISO 32000-2 §7.6 yanıtı /Perms girdisinde verir ve HotPDF onu kullanır: 16 baytlık /Perms dizgesini dosya şifreleme anahtarıyla AES-256 CBC, sıfır IV, dolgusuz çözün, sonra hiçbir şeye inanmadan önce düz metnin her alanını denetleyin. 1 ile 4 arası baytlar izin değerini little-endian sırada tutar ve /P tamsayısına tam olarak eşit olmalıdır; 5 ile 8 arası baytlar 0xFF değerindedir; 9. bayt T ya da F meta veri şifreleme bayrağıdır; 10 ile 12 arası baytlar adb değişmez işaretidir. Ancak bunların hepsi tuttuğunda PermissionsAuthenticated True olur ve 13. bit okunur; polaritesine dikkat edin, MAC gereksinimi 0x1000 biti temiz olduğunda bildirilir. /P ile çözülen izinler arasındaki uyumsuzluk günlüğe yazılıp geçilecek bir uyarı değildir; sahte bir izin kümesidir ve doğru yanıt kapalı başarısız olmaktır
Algoritma çevikliği özet düzeyinde durur
ISO/TS 32004 belge özetini seçmenize izin verir ve yalnızca belge özetini. HotPDF, kimlik doğrulama için HMAC-SHA-256, anahtar türetme için RFC 5869 uyarınca HKDF-SHA-256 ve anahtar sarma için RFC 3394 uyarınca AES-256 key wrap öğelerini sabit tutar; üzerinde pmdaSHA256 ile pmdaSHA3_512 arasında değişen bir THPDFPDFMACDigestAlgorithm durur. Doğal hata, «SHA3-512 profili» ifadesini HMAC öğesini de değiştirme lisansı saymaktır; bu, birlikte çalışabilir anlamda artık PDF MAC olmayan bir dosya üretir. Kendi doğrulayıcınızı yazıyorsanız kopyalamaya değer bir gerçekleme ayrıntısı: bayt aralığını karma yapmadan önce özet OID değerini CMS AuthenticatedData içinden okuyun; çünkü SHA-256 öğesini sabit kodlayıp sonra uzlaştırmak çevikliği bir etikete dönüştürür ve düşmanca bir dosyanın, algoritmanın hiç desteklenmediğini keşfetmeden önce size tüm belgeyi akıtmasına izin verir. CMSAlgorithmProtection, AuthenticatedData özet algoritması, bütünlük bilgisi messageDigest ve bayt aralığı özeti aynı algoritmayı adlandırmalıdır; herhangi bir uyuşmazlık kapalı başarısız olur
var
Options: THPDFPDFMACOptions;
begin
Options := THPDFPDFMACOptions.Compatibility; // SHA-256, altısını da kabul eder
Options := THPDFPDFMACOptions.Modern; // SHA-384, 256 biti reddeder
Options := THPDFPDFMACOptions.HighAssurance; // yalnızca SHA3-512, AES-GCM
// Özel bir profil yasaldır ama üretimde kullandığı algoritmanın
// doğrulama izin listesinde de görünmesi gerekir; yoksa yapılandırma
// tek bir bayt yazılmadan reddedilir
Options.Profile := pmppCustom;
Options.DigestAlgorithm := pmdaSHA512;
Options.AllowedDigestAlgorithms := [pmdaSHA512, pmdaSHA3_512];
Options.RequireAESGCM := True;
end;
PDF MAC neyi kanıtlar ve neyi kanıtlamaz
Doğrulanmış bir PDF MAC zinciri, korumalı her revizyonun dosya şifreleme anahtarını elinde tutan birinin yazdığıyla bayt bayt aynı olduğunu, hiçbir korumalı revizyonun kaldırılmadığını ya da yeniden sıralanmadığını ve çapadan sonra hiçbir korumasız revizyonun eklenmediğini kanıtlar — tam da düz AES-256 şifrelemenin açık bıraktığı saldırı sınıfı; çünkü gizlilik bütünlük hakkında hiçbir şey söylemez ve eklenmiş revizyonlu şifreli bir PDF, sağlamı kadar mutlu biçimde çözülür. Kanıtlamadığı şey yazarlıktır. MAC anahtarı dosya şifreleme anahtarından türetilir; bu yüzden belgeyi açabilen herkes, meşru her alıcı dahil, değiştirilmiş bir sürüm üzerinde geçerli bir MAC üretebilir. Simetrik bir temeldir ve simetrik temeller atıfta bulunamaz. Bir şeyi kimin değiştirdiğini bilmeniz gerekiyorsa arkasında sertifika olan bir dijital imza gerekir ve PDF MAC sonra onu, imzanın tek başına kapsamadığı artımlı yapıyı koruyarak tamamlar. İkisini katman olarak ele alın ve iki kararın tek bir durum simgesine birleştirilmesi yerine bağımsız raporlanmasına izin verin
Burada anlatılan PDF MAC giriş noktaları — AddStandalonePDFMAC, SignPDFWithPFXAndAttachedPDFMAC, ValidatePDFMAC ve ValidatePDFMACChain — Delphi ve C++Builder için standart HotPDF Delphi Component paketiyle gelir; ürün sayfası seçenekler kaydı, durum numaralandırmaları ve revizyon başına doğrulama dizisi için tam başvuruyu taşır