PDFlibPas, FieldMDP sorusunu TPDFlib.GetSignatureModificationVerdict üzerinden yanıtlar. İmzalı bir PDF, parolası ve bir imza alanı adı verildiğinde metot, o imzadan sonra eklenen her artımlı güncellemeyi gezinir, bu güncellemelerin dokunduğu her form alanının tam nitelikli adını (fully qualified name) çözer; FieldMDP tarafından kilitlenmiş bir alan değiştirildiyse 3, yalnızca kilitsiz alanlara dokunulduysa 2 döndürür. GetSignatureModificationDetail ise revizyonu ve alanı adıyla raporlar
Bu yanıtı gerektiren iş akışı çok onaylı formdur. Talep eden kişi satın alma talebinde Order.Customer ile Order.Total alanlarını doldurur ve Approval.Requester alanını imzalayarak o iki alanı kilitler. Bir yönetici maliyet merkezi ekler ve Approval.Manager alanını imzalar. İki hafta sonra biri dosyayı bir masaüstü düzenleyicide açar ve üçüncü artımlı güncellemede Order.Total değerini yukarı çeker. Her imza yalnızca kendi byte aralığını kapsadığı için doğrulamadan geçmeye devam eder. Denetçinin gerçekten sorduğu sorular ise hangi alanın hangi imzadan sonra değiştiği ve bu değişikliğe izin verilip verilmediğidir
DocMDP tek başına düzenlenmiş kilitli bir alanı neden yakalayamaz?
DocMDP bunu yakalayamaz çünkü DocMDP değişiklik türlerini sınıflandırır, tek tek alanları değil. ISO 32000-1 §12.8.2.2 bölümündeki sertifikasyon izin düzeyleri, sonraki güncellemelerin formları doldurup imzalayabileceğini (P 2) yoksa ayrıca açıklama da ekleyebileceğini (P 3) söyler ve bu izin belgedeki her alana eşit uygulanır. Order.Total alanını düzenlemek form doldurmaktır; dolayısıyla P 2 sertifikasyonu, talep edenin yasaklamak istediği düzenlemeyle tam olarak tatmin olur. PDFlibPas'ta belge düzeyinde değişiklik sınıflandırması o katmanı kapsar, bu makale ise bir adım daha inceye iner
FieldMDP alan ayrıntı düzeyindeki katmandır. Bir imza alanı /Lock sözlüğü taşıyabilir (ISO 32000-1 §12.7.4.5); taşıdığı imza da imza referansında bir FieldMDP dönüşümü barındırabilir (ISO 32000-1 §12.8.2.4). İkisi aynı sözcük dağarcığını kullanır: /Action /All her alanı kilitler, /Action /Include /Fields içinde listelenen adları kilitler, /Action /Exclude ise /Fields içindekiler dışındaki her şeyi kilitler. v3.586.0 öncesinde GetSignatureModificationVerdict, sonraki bir revizyonun bir form alanını değiştirdiğini biliyor ama hangisi olduğunu bilmiyordu; bu yüzden alan kilidi taşıyan ve sonraki güncellemeleri doğrulama malzemesinin ötesine geçen her belge 4, yani belirsiz olarak dönüyordu. Revizyon haritası artık sınıflandırdığı her alanla ilgili nesne için çözülmüş bir alan adı kaydediyor; o 4'ü gerçek bir 2 ya da 3'e çeviren de tam olarak bu
Her onaycı imzalarken alan kilidini yazmak
TPDFlib.SetSignProcessFieldLock, bir imzalama sürecinin üreteceği sonraki imza için kilidi ayarlar. Action 1 All, 2 Include, 3 Exclude demektir, 0 ise kilidi temizler; Include ile Exclude, noktalı virgülle ayrılmış tam nitelikli alan adı listesi alır. İmzalanan alan bir /Lock sözlüğü ve onunla eşleşen bir FieldMDP dönüşümüyle sonuçlanır; katı doğrulayıcıların beklediği eşleşme budur
var
Pdf: TPDFlib;
SignId: Integer;
begin
Pdf := TPDFlib.Create;
try
SignId := Pdf.NewSignProcessFromFile('purchase-request.pdf', '');
if SignId = 0 then
raise Exception.Create('cannot open the form');
try
Pdf.SetSignProcessField(SignId, 'Approval.Requester');
Pdf.SetSignProcessPFXFromFile(SignId, 'requester.pfx', PfxPassword);
// 2 = Include: bu imza tarafından dondurulan alanlar yalnızca bunlar
if Pdf.SetSignProcessFieldLock(SignId, 2,
'Order.Customer;Order.Total') <> 1 then
raise Exception.Create('field lock rejected');
Pdf.EndSignProcessToFile(SignId, 'purchase-request-signed.pdf');
if Pdf.GetSignProcessResult(SignId) <> 1 then
raise Exception.CreateFmt('signing failed, code %d',
[Pdf.GetSignProcessResult(SignId)]);
finally
Pdf.ReleaseSignProcess(SignId);
end;
finally
Pdf.Free;
end;
end;
SetSignProcessFieldLock, ad verilmediğinde Include ya da Exclude çağrısı için 0 döndürür; 'Order.Customer;;Order.Total' gibi boş bir girdi barındıran liste de aynı sonucu alır. Reddedilen çağrı önceden yapılandırılmış kilidi yerinde bırakır; o yüzden son çağrının kazandığını varsaymak yerine dönüş değerini kontrol edin. İmzalama kurulumunun geri kalanı — özet (digest) seçimi, /Contents rezervasyonu ve sonuç kodları — PDFlibPas için PAdES imzalama ve doğrulama rehberinde ele alınır. Onay zincirlerine özgü bir tasarım noktası: talep eden imzasındaki bir /All kilidi Approval.Manager alanını da dondurur, çünkü imza alanı da bir form alanıdır. Onaycının sahip olduğu veri alanları için Include kullanın ya da sonraki imza alanlarını listeleyerek Exclude kullanın
Kararı bir onay zinciri boyunca çalıştırmak
GetSignatureModificationVerdict bir seferde tek bir imzayı yargılar; dolayısıyla bir onay zinciri, imza alanı başına bir çağrı yapılarak kontrol edilir. Dönüş değeri küçük ve kapalı bir kümedir ve her değer, inceleyen kişi için farklı bir şey ifade eder:
- 0: dosya ya da adı geçen imza alanı okunamadı
- 1: imzadan sonra hiçbir şey eklenmemiş
- 2: yalnızca etkin izinlerin izin verdiği değişiklikler eklenmiş ve kilitli hiçbir alana dokunulmamış
- 3: sonraki bir revizyon izin verilmeyen bir değişiklik yapmış; FieldMDP'nin kilitlediği bir alanın düzenlenmesi de buna dahil
- 4: yanıt belirlenemedi; bu kesinlikle onay olarak okunmamalı
- 5: imza bir revizyon sınırında bitmiyor; byte'lar kapsadığını iddia ettiği aralığın içinde duruyor
const
Approvals: array[0..2] of WideString =
('Approval.Requester', 'Approval.Manager', 'Approval.Finance');
var
Pdf: TPDFlib;
I, Verdict: Integer;
begin
Pdf := TPDFlib.Create;
try
for I := Low(Approvals) to High(Approvals) do
begin
Verdict := Pdf.GetSignatureModificationVerdict(
'purchase-request-final.pdf', FormPassword, Approvals[I]);
// iki getter da az önce yapılan çağrıyı anlatır; sonraki çağrıdan önce okuyun
Log.Add(Format('%s: verdict %d, MDP level %d, %s',
[Approvals[I], Verdict, Pdf.GetSignatureEffectiveMDPLevel,
Pdf.GetSignatureModificationDetail]));
case Verdict of
1, 2: ; // kabul edildi
3: RejectForm(Approvals[I]); // detail, alanı ve revizyonu adıyla verir
else
QueueForManualReview(Approvals[I]); // 0, 4, 5
end;
end;
finally
Pdf.Free;
end;
end;
Kurcalanmış satın alma talebini ele alın: revizyon 0 boş form, revizyon 1 ile 2 iki imza, revizyon 3 ise düzenlemedir. Kilit tanımları imzalanmış her alandan havuzlandığı için Approval.Manager kararı zaten talep edenin kilidini uygular ve onun sonraki tek güncellemesi düzenlemenin kendisidir. O güncelleme yalnızca alan sözlüğünü yeniden yazdığında karar 3 olur ve detay Revision 3 changed locked form field "Order.Total", which FieldMDP does not allow. iletisini verir. Tek satır her iki denetim sorusunu da yanıtlar. Approval.Requester kararı önce yöneticinin imzaladığı revizyonu geçmek zorundadır ve aşağıdaki sınırlamalar bölümündeki nedenlerle çoğu zaman 4 raporlar; en net yanıtı genellikle en son imza verir. GetSignatureEffectiveMDPLevel, imzalar arasında bulunan en düşük DocMDP P değerini raporlar; belgeyi hiçbir şey sertifikalamamışsa 3 verir ve her iki getter da yalnızca bir sonraki karar çağrısına kadar geçerlidir
PDFlibPas bir revizyonun hangi alanı değiştirdiğini nasıl bilir?
PDFlibPas alan adını her revizyonun nesne grafiğinden yeniden kurar, çünkü değişen bir nesne tam adını nadiren taşır. /FT ya da /V barındıran bir alan sözlüğü ya da bir widget açıklaması, kısmi adını yalnızca /T içinde tutar. ISO 32000-1 §12.7.3.2 bölümünde tanımlanan tam nitelikli ad, kökten itibaren noktalarla birleştirilen kısmi ad zinciridir; revizyon haritası bu yüzden /Parent bağlarını yukarı doğru gezinir ve bulduğu her /T'yi öne ekler. Her ebeveyn, sınıflandırılan revizyondaki ya da ondan önceki en yeni tanımından okunur; böylece bir ebeveyn düğümün sonradan adının değiştirilmesi, önceki düzenlemelerin geçmişini yeniden yazamaz
Çözülen adı kilitlerle eşleştirmek bilinçli olarak basittir. Bir ad, bir /Fields girdisiyle tam eşit olduğunda ya da girdiyle nokta eklenerek başladığında o girdiyle eşleşir; dolayısıyla Order alanını kilitlemek Order.Total ve öteki tüm alt alanları da kilitler. All her adı kilitler, Include eşleşen adları kilitler, Exclude eşleşmeyen her adı kilitler. Kilit tanımları dosyadaki imzalanmış her imza alanından gelir; bir alan hem /Lock sözlüğü hem FieldMDP dönüşümü barındırıyorsa /Lock değerleri kullanılır. Her imzanın tam olarak neyi kilitlediğini görmek için, daha alt düzeydeki PDFlibDigitalSign ünitesindeki TPDFlibSignDoc sınıfı, kararın okuduğu izin raporunu açar:
uses
PDFlibDigitalSign;
var
SignDoc: TPDFlibSignDoc;
Report: TPDFlibSignaturePermissionReport;
Names: TStringList;
I, J: Integer;
Line: string;
begin
SignDoc := TPDFlibSignDoc.Create;
Names := TStringList.Create;
try
if not SignDoc.Open('purchase-request-final.pdf', FormPassword, False) then
Exit;
try
SignDoc.GetSignatureFieldNames(Names);
for I := 0 to Names.Count - 1 do
begin
SignDoc.GetSignaturePermissionInfoByName(Names[I], Report);
if not (Report.HasFieldLock or Report.HasFieldMDP) then
Continue;
Line := Names[I] + ': ' + string(Report.FieldLockAction);
for J := 0 to High(Report.FieldNames) do
Line := Line + ' ' + string(Report.FieldNames[J]);
if Report.HasFieldLock and Report.HasFieldMDP and
not Report.FieldMDPMatches then
Line := Line + ' (lock and FieldMDP transform disagree)';
Log.Add(Line);
end;
finally
SignDoc.Close;
end;
finally
Names.Free;
SignDoc.Free;
end;
end;
Şifreli formlar: parolayı iletin ya da adlar okunamaz
Şifreli bir formda herhangi bir alan adı çözülebilmesi için önce şifrenin çözülmesi gerekir; dolayısıyla GetSignatureModificationVerdict, Password argümanına yalnızca dosyayı açmak için değil daha fazlası için ihtiyaç duyar. /T gibi dizeler nesne başına şifrelenir ve sıkıştırılmış nesne akışlarına yazılmış alanlar, kapsayan akışın şifresi çözülüp açılıncaya dek hiç okunamaz. v3.586.0'dan bu yana dahili revizyon haritası parolayı kabul eder, nesne akışlarını ve revizyon sözlüklerini ayrıştırırken bir şifre çözme bağlamı ekler ve kodunu çözdüğü her nesnenin şifresini açar; buna karşılaştırma yaptığı önceki sürümler ile gezindiği ebeveynler de dahildir
Revizyon haritasındaki nesne başına şifre çözme, yalnızca Password boş olmadığında devreye girer. Bu yüzden şifreli bir dosya üzerinde boş parolayla hesaplanan bir karar, belge kendisi sormadan açılmış olsa bile doğrulanmamış sayılmalıdır. Form parolasını iş akışı kaydının yanında saklayın ve her çağrıda iletin
FieldMDP kararının kapsamadıkları
Alan kontrolü dar tek bir soruya verilen yapısal bir yanıttır ve birkaç durum onun dışında kalır. Bunları önceden bilmek, bir 4'ün destek tırmandırmasına dönüşmesini önleyen şeydir:
- Alan karşılaştırması yalnızca belge düzeyindeki kontrol temiz çıktıktan ve sonraki en az bir revizyon, doğrulama malzemesi ya da zaman damgalarının ötesinde bir şey değiştirdikten sonra çalışır; DocMDP ihlali, hiçbir alana bakılmadan 3 olarak rapor edilir
- İmza değeri sözlüğü, yeniden yazılmış bir AcroForm sözlüğü ya da
/AcroFormveya/Permsile sınırlı bir katalog değişikliği gibi imzayla ilgili sınıflandırılan ama alan adı taşımayan nesneler, kararın tahmin etmek yerine 4 döndürmesine neden olur; etkin bir kilit altında sonraki bir onay imzası ekleyen revizyon bu yüzden çoğu zaman 4'e düşer - Yalnızca alan sözlükleri ve widget açıklamaları alan adı alır; revizyon haritasının görünüm akışları (appearance stream) için ayrılmış bir sınıfı yoktur, bu yüzden değille birlikte görünümleri de yeniden üreten bir düzenleyici, alan kontrolü çalışmadan belge düzeyindeki kontrol tarafından içerik değişikliği olarak durdurulabilir; detay dizisi bu iki durumu birbirinden ayırır
- Tarama, karşılaştığı ilk kilitli alanda ya da adsız girdide durur; bir 3, suçlu alanlardan yalnızca birini adlandırır, hepsini değil
- Kilitler, zaman sırasına sokulmadan imzalanmış her imza alanından havuzlanır; bu yüzden sonradan imzalayan birinin yazdığı kilit, kendinden önceki güncellemelere de uygulanır. Bu, bir sonucu yalnızca 3'e doğru itebilir, asla 2'ye doğru değil
- Adlar tam ve büyük/küçük harfe duyarlı karşılaştırılır ve
/Parentgezinmesi sekiz düzeyden sonra durur; alışılmadık ölçüde derin bir hiyerarşi bu yüzden kırpılmış bir ada çözülür - Yapısı doğrulamayı geçmeyen ve eylemi okunamayan bir FieldMDP girdisi, kararın 4 döndürmesine neden olur
Bir karar 4 olarak döndüğünde GetSignatureRevisionIndex, imzanın bittiği revizyonu verir; GetDocumentRevisionChanges ise her sonraki revizyonun eklediği, değiştirdiği ya da serbest bıraktığı her nesneyi değişiklik sınıfıyla birlikte listeler. Bir kişinin bir dakikada karar vermesi için bu yeter. Söz konusu revizyonların nasıl eklendiğinin mekaniği PDFlibPas için artımlı güncelleme rehberinde ele alınır
SSS
2 kararı imzaların geçerli olduğu anlamına gelir mi?
Hayır. GetSignatureModificationVerdict, bir imzadan sonra ne eklendiğini inceler ve CMS imza değerine, sertifika zincirine ya da iptal (revocation) bilgisine hiç bakmaz. 2, sonraki güncellemelerin izinler içinde kaldığını söyler; kriptografik doğrulama ayrı bir adımdır ve ikisi de gerekir
İkinci onaycının imzalaması neden 2 yerine 4 üretir?
İmzalama, bir imza değeri sözlüğü ekler ve genellikle AcroForm sözlüğü gibi form defter tutmasını yeniden yazar. O nesneler adı geçen hiçbir alana ait değildir ve alan kilidi etkinken karar, bir alana atfedemediği değişikliği temizlemeyi reddeder. Revizyonun yalnızca beklenen imza nesnelerini içerdiğini teyit etmek için GetDocumentRevisionChanges kullanın
Tek bir ad, bir alan grubunun tamamını kilitleyebilir mi?
Evet. Bir kilit girdisi, adı geçen alanla ve tam nitelikli adı onunla nokta eklenerek başlayan her alt alanla eşleşir; dolayısıyla bir Include kilidinde Order listelemek, Order.Customer, Order.Total ve o ebeveynin altındaki öteki tüm alanları dondurur
FieldMDP kararları, alan kilidi imzalaması ve revizyon incelemesinin tamamı PDFlibPas Delphi PDF Library ile gelir; yukarıdaki onay iş akışının dayandığı DocMDP sertifikasyonu ve PAdES uzun vadeli doğrulama özellikleri de aynı pakette