Teknik Makale

PDFium: HSM ve Bulut Anahtarlarıyla Uzaktan PAdES İmzalama

PDFiumPas, PAdES imzalamayı iki çağrıya böler; böylece özel anahtarın hiçbir zaman sizin sürecinizde olması gerekmez. PreparePadesRemoteSignature, boş sabit genişlikli bir /Contents yer tutucusuyla artımlı bir güncelleme yazar ve SHA-256 belge özetini, tam ByteRange'i ve hazırlanmış dosyanın bir parmak izini taşıyan bir istek kaydı geri verir. CompletePadesRemoteSignature, imzalama servisinizin döndürdüğü ayrık CMS'yi alır ve o rezerve edilmiş yuvaya bırakır

Bu iki çağrı arasında dakikalar ya da saatler geçebilir, süreç yeniden başlayabilir ve iş başka bir makineye taşınabilir. Bu boşluk, API'nin bu şekilde tasarlanmasının tüm nedenidir

Uzak bir anahtar neden sıradan imzalama çağrısını kullanamaz?

Çünkü SignPadesBytes, imzalama işleminin çağrının içinde gerçekleştiğini varsayar. Artımlı güncellemeyi inşa eder, özeti ByteRange üzerinden hesaplar, imzalar ve sonucu yazar; hepsi dönmeden önce. Bu, anahtar Windows sertifika deposunda ya da yüklediğiniz bir PKCS#12 dosyasında yaşadığında tam olarak doğrudur

Anahtar bir ağ HSM'sinde, bir güven hizmeti sağlayıcısının işlettiği nitelikli bir imza oluşturma cihazında ya da kullanıcının bir telefonda onaylamasını gerektiren bir bulut imzalama API'sinde yaşadığında ise imkânsızdır. Bu durumlarda dizi bir fonksiyon çağrısı değil bir sohbettir: bir özet gönderirsiniz, başka bir şey bir insanı doğrular ve bir CMS daha sonra geri gelir. Eşzamanlı bir API, bir iş parçacığını ikinci bir faktör gerektirebilecek bir işlemde bloklamadan "daha sonra"yı ifade edemez

İki aşamalı protokol

Birinci aşama belgeyi hazırlar. PDFiumPas, imza alanını ve değer sözlüğünü ekler, /Contents içinde ContentsSize bayt onaltılık kodlanmış alan rezerve eder, o rezervasyon çevresindeki ByteRange'i hesaplar ve FormatVersion, PreparedFingerprint, DocumentDigest, dört öğeli ByteRange, ContentsHexOffset ve ContentsSize içeren bir TPadesRemoteSigningRequest üretir

İmzalama servisinizin ihtiyaç duyduğu tek değer DocumentDigest'tir: döndürülen CAdES SignedData'nın ileti özeti olarak taşıması gereken SHA-256. Kayıttaki geri kalan her şey, ikinci aşamanın tamamladığı dosyanın o özetin hesaplandığı dosya olduğunu kanıtlayabilmesi içindir

uses
  FPdfPades;

var
  Options: TPadesRemoteSignOptions;
  Request: TPadesRemoteSigningRequest;
  Source, Prepared, Session: TFileStream;
begin
  Options := TPadesRemoteSignOptions.Default;
  Options.Reason := 'Approved by finance';
  Options.Location := 'Lisbon';
  Options.Name := 'A. Moreira';
  Options.SigningTimeUtc := NowUtc;
  Options.ContentsSize := 16384;   // CMS için rezerve edilen onaltılık bayt

  Source := TFileStream.Create('contract.pdf', fmOpenRead or fmShareDenyWrite);
  Prepared := TFileStream.Create('contract.prepared.pdf', fmCreate);
  try
    PreparePadesRemoteSignature(Source, Prepared, Options, Request);
  finally
    Prepared.Free;
    Source.Free;
  end;

  // Oturumu sakla, böylece sonraki bir çalıştırma - ya da başka bir makine - tamamlayabilir
  Session := TFileStream.Create('contract.signreq', fmCreate);
  try
    SavePadesRemoteSigningRequest(Session, Request);
  finally
    Session.Free;
  end;

  SendDigestToSigningService(Request.DocumentDigest);
end;

Complete neyi reddeder ve her kontrol neden vardır?

Tamamlama, uzak imzalama tasarımının genellikle yanlış gittiği yerdir; bu yüzden doğrulama bilinçli olarak affetmezdir. CompletePadesRemoteSignature; parmak izi artık istekle eşleşmeyen hazırlanmış bir PDF'i, kayıtlı yer tutucu koordinatlarıyla eşleşmeyen bir ByteRange'i, değiştirilmiş /Contents sınırlayıcılarını, artık boş olmayan bir yer tutucuyu, rezervasyondan büyük bir CMS'yi, tam olarak tek bir DER değeri olmayan bir CMS'yi, desteklenmeyen bir SignedData biçimini, eksik bir signing-certificate-v2 özniteliğini ve ileti özeti hazırlanan belge özetine eşit olmayan bir CMS'yi reddeder

Bunların her biri gerçek bir başarısızlığa karşılık gelir. Parmak izi ve ByteRange kontrolleri, birinin iki aşama arasında hazırlanmış dosyayı yeniden ürettiği durumu yakalar; bu, kimsenin baytlarına sahip olmadığı bir şeye karşı doğrulanacak bir imza üretirdi. Boş yer tutucu kontrolü, çift tamamlamayı yakalar; burada ikinci bir CMS, zaten var olan bir imzanın üzerine yazılır. İleti özeti kontrolü ise en tehlikeli durumu yakalar: doğru biçimde oluşturulmuş ama farklı bir belge üzerinde imzalanmış bir CMS; bu, bir kuyruk iki eşzamanlı imzalama oturumunu karıştırdığında elde ettiğiniz şeydir. Bu olmadan, imzalanmış görünen ve her yerde doğrulaması başarısız olan ya da daha kötüsü, başka birinin onayını taşıyan bir dosya üretirdiniz

Signing-certificate-v2 gereksinimi, bir bütünlük meselesinden çok bir PAdES uyumluluk meselesidir. ETSI EN 319 142, imzalayan sertifikanın imzalı özniteliklere bağlanmasını gerektirir ve bu özniteliği taşımayan bir CMS, kriptografik olarak doğrulansa bile bir PAdES imzası değildir. Bunu tamamlamada reddetmek, bunu burada öğrenmeniz, bir müşteriden gelen bir doğrulayıcı raporunda değil, anlamına gelir; bu konu doğrulayıcılar neden PAdES imzalarını reddeder'de daha ayrıntılı incelenmiştir

var
  Request: TPadesRemoteSigningRequest;
  Session, Prepared, Dest: TFileStream;
  CmsDer: TBytes;
begin
  Session := TFileStream.Create('contract.signreq', fmOpenRead);
  try
    Request := LoadPadesRemoteSigningRequest(Session);
  finally
    Session.Free;
  end;

  CmsDer := FetchDetachedCmsFromService;   // HSM ya da TSP tarafından döndürülür

  Prepared := TFileStream.Create('contract.prepared.pdf', fmOpenRead);
  Dest := TFileStream.Create('contract.signed.pdf', fmCreate);
  try
    try
      CompletePadesRemoteSignature(Prepared, Dest, Request, CmsDer);
    except
      on E: EPadesCrypto do
        // Her reddetme belirli bir neden taşır; bunu birebir günlüğe kaydet
        FailSession(E.Message);
    end;
  finally
    Dest.Free;
    Prepared.Free;
  end;
end;

Süreç ve makine sınırlarını aşmak

SavePadesRemoteSigningRequest ve LoadPadesRemoteSigningRequest, oturumu kararlı, sürümlü bir ikili biçim üzerinden serileştirir; tasarımı yalnızca doğru değil pratik kılan da budur. Bir web uygulaması bir istekte bir belge hazırlayabilir, hazırlanmış PDF'i ve oturum ikili verisini saklayabilir, bir akıllı kart imzası için tarayıcıya bir özet döndürebilir ve dosyayı tamamen farklı bir istek işleyicisinde tamamlayabilir

FormatVersion alanı, bunu yükseltmeler arasında güvenli tutan şeydir. Eski bir derleme tarafından yazılmış ve yeni bir derleme tarafından yüklenen bir oturum, farklı biçimli bir kayıt olarak yanlış okunmak yerine açıkça tanınır ya da reddedilir. Kuyruğunuz oturumları günlerce tutabiliyorsa, biçim sürümünü bir uygulama ayrıntısı değil günlüğe kaydetmeye değer operasyonel bir gerçek olarak ele alın

Yer tutucuyu boyutlandırmak

ContentsSize, düşünmeniz gereken tek parametredir, çünkü CMS var olmadan önce sabitlenir. Onaltılık kodlanmış rezervasyonu sayar; bu yüzden 6 KB'lık bir DER CMS en az 12 KB alana ihtiyaç duyar ve uygulama rezervasyonu 64 MiB ile sınırlar

Çok az rezerve edin, tamamlama, imzalama servisiniz işini zaten yaptıktan sonra aşırı boyutlu CMS hatasıyla başarısız olur; bu, ölçülü nitelikli imza servisinde boşa giden bir işlem anlamına gelir. Çok fazla rezerve edin, her imzalanmış belge dolguyu sonsuza kadar taşır. Makul yaklaşım ölçmektir: gerçek sertifika zincirinizle bir belge imzalayın, DER uzunluğuna bakın, onaltılık için ikiye katlayın, sonra bir T seviyesi imzaya yükseltmeyi düşünüyorsanız zaman damgası jetonu için cömert bir pay ekleyin. Birkaç ara sertifikaya ve uzun bir OCSP yanıtına sahip zincirler insanların beklediğinden daha hızlı büyür

İmzadan sonra ne gelir

Tamamlanmış bir uzak imza PAdES B-B'dir. Uzun vadeli doğrulama bir zaman damgası ve doğrulama malzemesi gerektirir; bu, bir DSS ve sayfa başına VRI sözlüklerini ekleyen ayrı bir artımlı güncellemedir; RFC 3161 zaman damgaları ve DSS ile uzun vadeli imzalarda anlatılmıştır. Bu adım yereldir: sertifikalar, OCSP yanıtları ve CRL'ler ekler; hiçbiri özel anahtara ihtiyaç duymaz

Göndermeden önce, ürettiğinizi bir ilgili tarafın kullanacağı aynı kod yoluyla doğrulayın; bu, dijital imzaları ve PAdES seviyelerini incelemede ele alınmıştır. İmzalama ve doğrulama farklı kodlardır ve uzak bir imzalama hattı, harici bir doğrulayıcı söyleyene kadar kimsenin fark etmeden ikisinin birbirinden ayrılabileceği tam yerdir

PDFiumPas, yerel bir Pascal PAdES yığınına sahip, PDFium motoru etrafında bir Delphi ve Lazarus bileşenidir; bu yüzden imzalama, zaman damgalama ve doğrulama harici komut satırı araçları olmadan çalışır. Tam API belgeleri ve bir deneme sürümü PDFium Delphi bileşeni sayfasında bulunur