PDFium VCL, RFC 3161 zaman damgası isteklerini Windows dışı hedeflerde libcurl üzerinden gönderir; sekiz sembole dinamik olarak bağlanır ve WinHTTP'ye bağlanan Windows backend'inin şeklini yansıtır. İki option ayarı, taşımanın yük altında güvenilir olup olmayacağına karar verir ve bütün unit, hedef platformu için onu derleyemeyen bir makinede doğrulandı
Zaman damgası, bir imzayı sertifika süresi dolsa da hayatta kalacak bir şeye çeviren şeydir ve bir imzalama işleminin içinde oturan bir ağ işlemidir. Bu bileşim, taşıma seçimini genellikle olmadığı bir şekilde kader belirleyici kılar: worker thread'de çalışır, denetlemediğiniz bir sunucuyla konuşur ve oradaki bir takılma sayfa yüklemesini değil imzalama hattını durdurur
FPC HTTP istemcisi yerine neden libcurl?
Çünkü alternatif, depoya bir TLS yığını çeker ve sonra sizin sürüm tespitini sürdürmenizi sağlar. Free Pascal'da bariz yol, OpenSSL socket katmanlı fphttpclient'tır ve ayrıntılarda kalır: FPC 3.2.2 OpenSSL bağlamaları, güncel dağıtımların çoğunda OpenSSL 3.x'i güvenilmez biçimde tespit eder ve macOS üstüne LibreSSL farklarını ekler. Küçük bir HTTP çağrısı olarak başlayan iş, başkasının TLS ABI'sinin sürekli bakımı olur
libcurl kendi TLS backend'ini kendisi seçer ve zincirleri platform trust store'una karşı doğrular; Pascal tarafı bunların hiçbirine ihtiyaç duymaz. Bağlama katmanı sekiz semboldür. O sayı argümanın kendisidir: kodunuz ile hareketli bir bağımlılık arasındaki daha küçük yüzey, bir dağıtım yükseltmesinin sizi kırabileceği daha az yer demektir; mevcut Windows backend'iyle de örtüşür, o da bir avuç WinHTTP giriş noktasını aynı şekilde bağlar
uses
FPdfTsaFpc;
var
ReqDer, RespDer: TBytes;
begin
if not TsaHttpAvailable then
raise Exception.Create('no HTTP transport for timestamping');
Writeln('TSA transport: ', TsaHttpBackendName);
ReqDer := BuildTimeStampQuery(DocumentDigest);
if PostTimeStampQuery('https://tsa.example.org/tsr', ReqDer, RespDer) then
AttachTimeStampToken(RespDer)
else
raise Exception.Create('timestamp request failed');
end;
Bir C variadic işlevini Pascal'da bildirmek
curl_easy_setopt ile curl_easy_getinfo, C tarafında variadic'tir ve Object Pascal bunu ifade etmenin bir yoluna sahip değildir. İşleyen yaklaşım, argüman sınıfı başına bir tane olmak üzere birkaç sabit prototip bildirmektir; hepsi aynı export sembolünü işaret eder: long alan bir varyant, pointer alan bir varyant ve devamı; çağrı noktasında gerçekte geçirdiğiniz şeye göre seçilir
Bu, ezberlenmekten çok anlaşılmasına değer özgül bir nedenle güvenlidir. O argüman türlerinin her biri, devredeki platform çağırma konvansiyonları altında bir tamsayı register'ından geçer; C tarafındaki uygulamanın va_arg'ı tam oradan okur. Hile bu yüzden tamsayılar, pointer'lar ve handle'lar için geçerlidir ve farklı register'lardan seyahat eden floating-point argümanları için geçerli değildir. Kalıbın genellediği varsayımıyla double alan bir varyant eklemeyin
// Tek export sembolü, birkaç sabit prototip. Her varyant argümanını
// bir tamsayı register'ında geçirir; C tarafı onu oradan okur. Bir
// floating-point varyant çalışmaz ve eklenmemelidir
type
TCurlSetOptLong = function(Handle: Pointer; Option: Integer;
Value: NativeInt): Integer; cdecl;
TCurlSetOptPtr = function(Handle: Pointer; Option: Integer;
Value: Pointer): Integer; cdecl;
var
curl_easy_setopt_long: TCurlSetOptLong;
curl_easy_setopt_ptr: TCurlSetOptPtr;
İsteğin tamamlanıp tamamlanmayacağına karar veren iki ayar
Birincisi, açıkça yazılmış boş bir Expect: başlığıdır. libcurl, kabaca bir kilobaytı aşan istek gövdeleri için HTTP 100-continue el sıkışmasını açar ve sertifika isteği taşıyan bir zaman damgası sorgusu genellikle o eşiği geçer. Bazı TSA sunucuları devamı hiç cevaplamaz; istemci, sunucunun anında kabul edeceği gövdeyi göndermeden önce tam bir zaman aşımını bekleyip durur. Boş bir Expect: başlığı göndermek el sıkışmayı bastırır ve istek tek gidiş-dönüşte geçer
İkincisi, kurulması zorunlu olan CURLOPT_NOSIGNAL'dır. Olmadığında libcurl, isim çözümleme zaman aşımını SIGALRM ile uygular ve o mekanizma thread-safe değildir. İmzalama bir worker thread'de koşar; varsayılan davranış, eşzamanlılık altında beliren ve tek thread'li testte hiç belirmeyen örtük bir çökmedir. Bayrağı kurmak sinyal tabanlı yolu devre dışı bırakır ve bedeli yalnızca çözümleyici zaman aşımı granülitesidir
İki kusur da, sonradan bulunmasını pahalı kılan bir profile sahiptir. Ne biri, iyi huylu bir sunucuya karşı tek thread'de koşan fonksiyonel bir testte görünür ne öteki. İkisi de üretimde, belirli bir TSA'ya karşı, yük altında belirir. Bir ağ kütüphanesini bağlarken, varsayılanlarının süreciniz hakkında ne varsaydığını, eşleştiklerini varsaymadan önce okuyun
Derleyicinizin asla görmeyeceği kodu nasıl doğrularsınız?
Derleyiciye yine de gösterek; kontrollü bir kopya üzerinden. Buradaki geliştirme makinesinde Linux ya da macOS cross-compiler yoktur; bu yüzden zaman damgası unit'inin Windows dışı dalları normal bir derlemede asla kod üreteciye ulaşmaz. Hiç derlenmeyen kod, sessizce çürüyen koddur: paylaşılan bir türde yeniden adlandırma, değişmiş bir parametre listesi, eklenmiş bir unit bağımlılığı ve aylarca kimsenin fark etmediği
Teknik mekaniktir. Unit'i geçici bir dizine kopyalayın, yeniden adlandırın ve her Windows koşullusunu, hem {$IFDEF MSWINDOWS} biçimini hem {$IF DEFINED(MSWINDOWS) biçimini, hiç tanımlanmayan bir sembolle değiştirin. Sonra kopyayı derleyin. 3.828 satırın tamamı derlendiğinde, Windows dışı yolun var olan unit'leri kullandığını, backend işlevlerini eşleşen imzalarla çağırdığını ve kapsam içindeki türlere referans verdiğini kanıtlamış olursunuz. Bu, taşımanın çalıştığının kanıtı değildir ve size onu hedef platformdan başka hiçbir şey vermez. Kanıtladığı şey, dalın hâlihazırda kırık olmadığıdır; birikerek ilerleyen hata modu da zaten budur
Refik alışkanlık, libcurl unit'inin kendisini platform guard'larından arındırılmış tutmaktır; orada ona referans veren hiçbir şey olmasa da sıradan Windows derlemesine katılır. Günlük derleme böylece sözdizimini ve türlerini bedavaya denetlemeye devam eder. Yalnızca elinizde olmayan bir platformda derlenen unit, hiçbir derleyicinin denetlemediği unit'tir; aynı akıl, Delphi ve FPC cross-compiler tuzakları makalesinde anlatılan çapraz derleyici işinin tamamına uygulanır
Geri döneni sınıra bağlamak
Bir zaman damgası yanıtı küçük bir DER yapısıdır ve taşımanın onu dayatan bir yanı yoktur. Ele geçirilmiş, yanlış yapılandırılmış ya da yalnızca yanlış URL'ye yönlendirilmiş bir sunucu keyfi bir akış döndürebilir ve bağlantı kapanana dek okuyan bir istemci onu gönül rahatlığıyla biriktirir. Her iki taşıma da bu yüzden yanıta tavan çeker; sınırın doğru yeri burasıdır: taşımada reddetmek, aşırı büyük bir gövdenin hiç tahsis edilmesini önler; çözümleyici düzeyindeki bir kontrol ise bellek taahhüt edildikten sonra ancak tetiklenir
Aynı akıl URL için de geçerlidir. Backend, anlamlı biçimde konuşabildiği şemaları kabul eder; yapılandırma hatası böylece libcurl'e protokol desteğinin izin verdiği herhangi bir şekilde yorumlatılmak yerine net bir mesajla anında kalır
Taşımanın imzalama hikayesindeki yeri
Zaman damgası, uzun vadeli doğrulama hikayesinin bütünü değil ilk adımıdır. Token imzaya iliştirilmek zorundadır, doğrulama malzemesi document security store'a kaydedilmek zorundadır ve arşiv zaman damgaları, güncel olan zayıflamadan önce yenilenmek zorundadır. O bütün yay, RFC 3161 zaman damgaları ve DSS ile uzun vadeli PDF imzaları makalesinde ele alınır
Taşıma, daha geniş bir taşınabilirlik duruşunun da bir parçasıdır: native kütüphaneyi her hedefte yükleme makalesinde anlatılan yerli kütüphane yükleyicisi, aynı sorun sınıfını PDFium binary'sinin kendisi için ele alır. Her iki durumda da kalıp özdeştir: az sayıda sembolü dinamik bağla, neyin bağlanamadığını kesin bildir ve eksik bir bağımlılığın, uygulamayı başlatamayacak bir link hatasına dönüşmesine asla izin verme
Windows ve Windows dışı zaman damgası backend'lerinin ikisi de PDFium Delphi bileşeni ile gelir; hedefe göre seçilir, yapılandırmaya göre değil. Böylece Linux'ta bir Lazarus uygulaması ile Windows'ta bir Delphi uygulaması, farklı tesisat üzerinden aynı zaman damgalı imzayı üretir