Skip to content

PAdES PDF Signer

By Romi Fadli, S.Kom. 10 min read Security & Secrets
On this page
A signed PDF with a QR stamp, wrapped in four nested frames for the signature, its timestamp, the embedded validation data, and the archive timestamp

PAdES PDF Signer adalah service Python yang membubuhkan tanda tangan yang terlihat dan bermakna hukum pada PDF, dan memastikan tanda tangan itu masih bisa diverifikasi lama setelah semua sertifikat di belakangnya kedaluwarsa. Ia menandatangani sampai PAdES B-LTA — level arsip jangka panjang dari standar Eropa untuk tanda tangan PDF — sehingga dokumen membawa stempel waktunya sendiri, buktinya sendiri bahwa tak ada sertifikat di rantainya yang dicabut, dan stempel waktu arsip yang menaungi semuanya. Ia juga memverifikasi PDF dan melaporkan setiap tanda tangan di dalamnya.

Saya membangunnya karena tanda tangan yang hanya bisa dikonfirmasi lewat jaringan yang hidup adalah tanda tangan bertanggal kedaluwarsa. Pembaca yang membuka kontrak sepuluh tahun lagi bisa saja mendapati responder certificate authority sudah tiada dan sertifikat penanda tangan lama kedaluwarsa; tanda tangan itu tetap harus membuktikan siapa yang menandatangani, kapan, dan bahwa ia sah pada saat itu. Menaruh setiap keping bukti itu di dalam PDF adalah seluruh pekerjaan service ini.

Sekilas

Bahasa & frameworkPython, dengan FastAPI, pyHanko untuk tanda tangan PDF, dan aiohttp untuk transfer
ArsitekturTransaction Script Service
Versi2.11.3
StatusStabil, berjalan di production
BentukService HTTP tanpa state, dikirim sebagai satu executable, dipanggil oleh aplikasi penanda tangan
Kode sumberPrivat
Apa module ini dan bagaimana keadaannya.

Yang dikerjakannya

A. Menandatangani PDF dengan stempel yang terlihat

Service menerima PDF dan gambar stempel — sering kali QR code — menempatkan stempel di satu kotak pada halaman pilihan, lalu menandatangani dokumen dengan sertifikat milik penanda tangan sendiri. Tiap tanda tangan menjadi field baru dengan id unik, sehingga satu dokumen bisa ditandatangani beberapa orang secara bergantian tanpa mengusik tanda tangan sebelumnya.

B. Menanamkan bukti bahwa tanda tangan itu sah

Saat penandatanganan, service mengumpulkan setiap sertifikat di rantai beserta jawaban pencabutan yang menunjukkan tak satu pun dicabut, lalu menyimpannya di dalam PDF. Validator bertahun-tahun kemudian tak butuh jaringan untuk tahu bahwa tanda tangan itu baik saat dibuat.

C. Menyegel hasilnya dengan stempel waktu

Tanda tangannya sendiri distempel waktu oleh timestamp authority, yang membuktikan kapan ia dibuat; lalu document timestamp ditambahkan atas seluruh file, termasuk data validasinya. Stempel waktu arsip itulah yang membuat tanda tangan bisa hidup lebih lama dari algoritma dan sertifikat yang menopangnya.

D. Memverifikasi PDF bertanda tangan

Diberi PDF apa pun, service melaporkan setiap tanda tangan dan document timestamp di dalamnya: sah atau tidak, siapa yang menandatangani, kapan, untuk apa dan di mana, seberapa banyak dokumen berubah sesudahnya, dan apakah data validasi jangka panjangnya ada.

E. Menjauhkan rahasia penanda tangan dari setiap antrean dan log

Tak ada yang di hulu — antrean, job, log — yang pernah memegang passphrase penanda tangan dalam teks polos, dan passphrase itu hanya melayani satu tanda tangan yang menjadi alasan ia diberikan.

Antarmuka

KemampuanKegunaan
Tanda tanganimenandatangani PDF di balik satu presigned link sampai PAdES B-LTA dengan stempel yang terlihat, lalu meng-upload hasilnya ke link lain; mengembalikan id tanda tangan dan SHA-256 file yang ditandatangani
Verifikasimelaporkan setiap tanda tangan dan document timestamp di PDF yang di-upload
Readinessmemeriksa certificate authority, timestamp authority, dan storage secara paralel, lalu menyebut mana yang gagal
Antarmuka HTTP service ini.

Request penandatanganan menyebut dokumennya, stempelnya, halaman dan kotak tempat stempel diletakkan, alasan dan lokasinya, serta ke mana hasilnya ditulis.

Standar

StandarYang dijaminnya di sini
PAdES B-LTA (ETSI EN 319 142)tanda tangan yang tetap bisa diverifikasi setelah sertifikatnya kedaluwarsa, diperiksa dengan ETSI conformance checker
Tanda tangan CMS di PDF (ISO 32000)tanda tangan ditambahkan sebagai incremental update, sehingga tanda tangan sebelumnya tetap utuh
RFC 3161, Time-Stamp Protocolstempel waktu tanda tangan dan stempel waktu arsip dari otoritas terpercaya
RFC 5280 dan RFC 6960daftar pencabutan dan jawaban OCSP dikumpulkan saat penandatanganan dan disimpan di dokumen
PKCS#12key dan rantai penanda tangan diterima sebagai satu bundel terlindung
W3C Trace Context dan OpenTelemetrypenandatanganan, stempel waktu, dan pengambilan sertifikat tampil sebagai langkah di trace pemanggil
Standar yang dipatuhi service, dan yang dijamin masing-masing.

Di dalamnya

Service ini berbentuk Transaction Script Service: tiap endpoint adalah satu prosedur yang terbaca, berurutan, setiap langkah satu request — periksa pemanggil, buka key penanda tangan, ambil dokumen dan stempel, susun konteks validasi, tanda tangani, upload, catat — dan kerja tiap langkah tinggal di module yang dinamai menurut urusannya: persiapan, penandatanganan, trust, fetcher, verifikasi, kriptografi, telemetry. Ia dibundel menjadi satu executable, jadi container-nya tak membawa source code.

Keputusan rancangan

Level arsip adalah tujuannya, dan saya dua kali berganti bahasa untuk mencapainya. Versi pertama, dalam Python, sampai pada titik ketika pembaca PDF yang banyak dipakai menerima validasi jangka panjangnya, lalu tersendat di jalan menuju standar lengkapnya. Yakin bahwa jalan buntunya ada di tooling Python, saya memindahkan signer ke Node.js, dan di sana jumlah error di conformance checker turun dari tiga menjadi satu. Lalu batasnya terlihat: library Node.js hanya bisa menanamkan validasi jangka panjang dalam gaya Adobe yang lebih lama, bukan dalam struktur PAdES yang diwajibkan standar. Saya kembali ke Python dengan bekal pelajaran dari jalan memutar itu tentang cara data validasi harus dikumpulkan, dan versi berikutnya menandatangani sampai PAdES B-LTA penuh dengan nol error di laporan ETSI conformance checker.

Setiap keping bukti dikumpulkan sebelum menandatangani, tak diharapkan muncul belakangan. Dua kali validasi gagal saat penandatanganan karena jawaban pencabutan "terlalu baru" — lebih baru dari momen yang dipakai validator sebagai patokan. Perbaikan pertama: daftar pencabutan milik root, CA penanda tangan, dan timestamp authority diambil paralel sebelum menandatangani dan langsung diberikan ke konteks validasi; perbaikan kedua: toleransi kecil untuk selisih jam antar-service. Pemeriksaan pencabutan diatur wajib mendapat jawaban, jadi tak pernah ada tanda tangan yang ditanamkan dengan celah di buktinya. Sertifikat root tak dimasukkan ke dokumen, karena validator harus sudah memercayainya, bukan menerimanya dari file yang sedang dinilainya.

Tanda tangan menambah dokumen, tak pernah menulis ulang. Tiap tanda tangan ditulis sebagai incremental update, sehingga tanda tangan sebelumnya beserta perlindungannya tetap sama byte demi byte, dan satu dokumen bisa mengumpulkan tanda tangan dari beberapa orang. Writer-nya juga menerima PDF dengan tabel cross-reference campuran, jadi dokumen dari beragam tool bisa ditandatangani. Tiap tanda tangan mendapat field baru bernama UUIDv7 miliknya, dan nama itu sekaligus menjadi id tanda tangan yang dikembalikan ke pemanggil, sehingga catatan dan PDF selalu menunjuk tanda tangan yang sama. Stempel digambar tanpa border, supaya QR code tak berbingkai dua kali, dan kotaknya boleh dimulai dari nol, supaya bisa menempel rapat ke tepi halaman.

Rahasia penanda tangan tak pernah tersimpan di mana pun sepanjang jalan. Passphrase tetap terenkripsi sejak aplikasi memasukkan job ke antrean, jadi ia tak pernah mengendap di payload job atau log aktivitas. Service tak punya akses tetap miliknya sendiri ke certificate authority: otoritas itulah yang memutuskan, untuk tiap request dan tiap pemanggil, apakah key ini boleh dipakai, dan apa pun yang ditangani service demi satu tanda tangan tak bertahan lebih lama dari tanda tangan itu.

File berpindah lewat link, dan hanya ke storage yang dikenal service. Dokumen, stempel, dan tujuannya semuanya presigned link, jadi aplikasi tak pernah mengalirkan PDF melewati dirinya. Tiap link harus menunjuk persis origin storage dan bucket yang diharapkan — allowlist yang disimpan di source, bukan di konfigurasi — dan selain itu ditolak sebelum satu byte pun diambil. Respons membawa SHA-256 file yang ditandatangani, sehingga aplikasi bisa menemukan dokumen dari hash-nya.

Verifikasi ketat lebih dulu, dan menilai tiap tanda tangan pada momennya sendiri. Verifier mula-mula memeriksa bahwa yang di-upload memang PDF — header dan penanda akhirnya — dan menjawab file palsu dengan error client yang jelas, bukan kegagalan server. Tiap tanda tangan lalu divalidasi online secara ketat; bila gagal karena dunia sudah berubah sejak penandatanganan, ia dinilai ulang secara offline pada waktu penandatanganannya sendiri, dari data validasi yang tertanam di dokumen — persis bukti yang dijaga oleh level arsip. Trust root dibaca dari direktori yang di-mount, jadi memercayai root baru adalah perubahan deployment, bukan perubahan kode.

Telemetry harus dibuat layak dipercaya sebelum bisa dipercaya. Logging pindah dari menulis langsung ke Elasticsearch menjadi OpenTelemetry lewat collector, melanjutkan trace dari aplikasi yang memanggil service lalu meneruskannya ke timestamp authority dan certificate authority, sehingga satu tanda tangan tampil sebagai satu trace lintas empat service. Redaksi memeriksa nilai, bukan hanya nama field, jadi signature presigned link tak pernah sampai ke log apa pun nama field-nya. Tiga insiden membentuk sisanya. Kegagalan nyaris tak terlihat — 492 span tapi hanya 14 catatan log dalam setengah jam — jadi setiap request yang ditolak atau gagal kini melewati satu handler yang mencatatnya, dengan field alasan yang dijaga tetap string karena indeks pencarian sudah mengunci tipe field itu. Readiness probe menghasilkan 99,8 persen dari semua span, jadi ia dikeluarkan dari tracing. Dan di dalam executable hasil bundel, dua instrumentor mematikan dirinya diam-diam karena bundel itu tak membawa metadata paket yang mereka periksa; build kini menyalin metadata itu, dan pengambilan data pencabutan kembali tampil di trace. Metrics memakai delta temporality, yang diwajibkan exporter Elasticsearch milik collector.

Readiness memeriksa apa yang benar-benar dibutuhkan penandatanganan. Service baru siap bila root CA, CA penanda tangan, timestamp authority, dan storage semuanya menjawab, diperiksa paralel, dan jawaban belum siap menyebut mana yang gagal. Probe-nya langsung ke tiap service, bukan lewat proxy publik, sehingga tiap dependensi diukur di tempat ia sungguh berjalan.

Spesifikasi

MasukanPresigned link ke PDF, gambar stempel, dan tujuan; sertifikat penanda tangan dan passphrase-nya yang terlindungi; halaman, kotak, alasan, dan lokasi
HasilPDF bertanda tangan PAdES B-LTA yang di-upload ke tujuan; id tanda tangan dan SHA-256 untuk pemanggil; untuk verifikasi, laporan per tanda tangan
Tanda tanganCMS di PDF, SHA-256, incremental update, stempel yang terlihat, stempel waktu tanda tangan dan arsip, sertifikat dan data pencabutan yang tertanam
Bergantung padaCA penanda tangan untuk key penanda tangan dan data pencabutan, root CA, timestamp authority, dan storage kompatibel S3
Diverifikasi denganETSI conformance checker dan pembaca PDF yang banyak dipakai
ObservabilityTrace, log, dan metrics OpenTelemetry lewat OTLP
Berjalan sebagaiSatu executable yang dibangun di image container multi-stage, dengan konfigurasi dan trust root di-mount
Yang diterima, dikembalikan, dan dibutuhkan service.

Terkait

Certificate authority yang memegang key setiap penanda tangan dan menjawab pertanyaan pencabutan yang tertanam di setiap tanda tangan.

Timestamp authority yang memberi tanggal setiap tanda tangan dan menyegel arsipnya.

Service storage yang menerbitkan link tempat dokumen, stempel, dan hasil tanda tangan berpindah.

Ke mana trace satu tanda tangan yang melintasi empat service berakhir.

Istilah

PAdES
PDF Advanced Electronic Signatures: standar Eropa untuk tanda tangan digital di PDF, dirumuskan dalam level dari dasar sampai arsip jangka panjang.
B-LTA
Level arsip jangka panjang PAdES: tanda tangan dengan stempel waktu, data validasi yang tertanam, dan stempel waktu arsip atas seluruh dokumen.
Long-term validation
Menanamkan sertifikat dan jawaban pencabutan yang akan dibutuhkan validator, supaya tanda tangan bisa diperiksa tanpa menghubungi siapa pun.
Document timestamp
Stempel waktu yang dikenakan pada seluruh PDF, bukan pada satu tanda tangan, dan melindungi semua yang ditambahkan sebelumnya.
Incremental update
Menambahkan perubahan di akhir PDF tanpa menulis ulang, sehingga isi dan tanda tangan sebelumnya tetap persis seperti semula.
PKCS#12
Format file yang membundel private key dengan sertifikat dan rantainya, dilindungi password.

Technologies covered

  • Python
  • FastAPI
  • pyHanko
  • OpenTelemetry
  • OCSP
  • PAdES

About the author

Photo of Romi Fadli

Romi Fadli, S.Kom.

Solution Architect · Backend Engineer · Embedded Systems

In my day job I work as a solution architect. I design the system, lead the team that builds it — quality assurance, backend developers, a UI developer, DevOps and DevSecOps — and write the most critical modules myself, such as a certificate authority, a long-term PDF signer, and the core API of a personnel system.

I work across the whole stack that a running system actually needs. On the hardware side that means PCB design, microcontrollers, and embedded firmware — including RISC-V boards running FreeRTOS and Embassy, speaking MQTT over mutually authenticated TLS on a microcontroller with 64 KB of SRAM.

Most of my day-to-day work is software: Rust backends and API modules built on Clean Architecture, an OAuth2/OpenID Connect authorization server written from scratch, PAdES document signing, and certificate authorities — root CAs, timestamping authorities, and OCSP responders. I also build the frontends that sit on top of them.

Running all of that means infrastructure: Docker Compose stacks, networking, Mikrotik and RADIUS, observability with OpenTelemetry, and a steady habit of writing command-line tools and utilities for Linux when the existing ones do not fit.

Share

Enjoyed this?

Get an email when a new article is published.

Referenced by

A memory chip holding a key, circled by refresh arrows, beside a browser window where a signature stamp is being dragged into place on a PDF page

Aplikasi browser Vue dari platform penandatanganan dokumen: sesi disimpan di memori dan diperbarui oleh satu refresh berantrean, login PKCE, stempel ditaruh presisi di halaman PDF, verifikasi identitas dengan tantangan wajah, persetujuan client, dan administrasi berbasis role.

10 min read Read more →
A central core holding people, organisations, documents, and certificates, connected to eight surrounding services for storage, addresses, certificates, timestamps, the root, signing, thumbnails, and face challenges

Inti Laravel dari platform penandatanganan dokumen: memegang user, identitas, organisasi, sistem client, dokumen beserta versi bertanda tangannya, stempel, dan sertifikat, serta mengorkestrasi service yang menandatangani, menstempel waktu, merender, dan menyimpan — tanpa pernah memegang file.

9 min read Read more →
A locked offline host holding the root key, a signed revocation list crossing an air gap to a small publisher server, which serves the root certificate and the list to a validator

Service kecil yang hanya menerbitkan, menjaga root CA tetap bisa dijangkau tanpa bisa disentuh: ia menyajikan sertifikat root dan daftar pencabutannya, sementara key root dan setiap tanda tangan tetap di host offline — bisa dipakai project mana pun yang punya CA sendiri.

7 min read Read more →
A purple root circle linked to a blue and an orange intermediate circle, which lead to a signed document with a green seal and to a clock.

Aurograf

DevOps

Platform tanda tangan digital Pemerintah Kota Tangerang Selatan: penanda tangan membuktikan identitasnya, menandatangani PDF hingga PAdES B-LTA dengan sertifikat dari otoritas milik platform sendiri, dan siapa pun bisa memverifikasinya — versi 2, yang saya rancang, bangun, dan operasikan.

10 min read Read more →

Related Articles

A memory chip holding a key, circled by refresh arrows, beside a browser window where a signature stamp is being dragged into place on a PDF page

Aplikasi browser Vue dari platform penandatanganan dokumen: sesi disimpan di memori dan diperbarui oleh satu refresh berantrean, login PKCE, stempel ditaruh presisi di halaman PDF, verifikasi identitas dengan tantangan wajah, persetujuan client, dan administrasi berbasis role.

10 min read Read more →
A central core holding people, organisations, documents, and certificates, connected to eight surrounding services for storage, addresses, certificates, timestamps, the root, signing, thumbnails, and face challenges

Inti Laravel dari platform penandatanganan dokumen: memegang user, identitas, organisasi, sistem client, dokumen beserta versi bertanda tangannya, stempel, dan sertifikat, serta mengorkestrasi service yang menandatangani, menstempel waktu, merender, dan menyimpan — tanpa pernah memegang file.

9 min read Read more →
A document's fingerprint passing through a clock, signed by a certificate below it, and returning as a time seal stamped on the same document

Timestamp authority berbahasa Rust yang menstempel hash dokumen dengan waktu bertanda tangan berbasis NTP sesuai RFC 3161, supaya tanda tangan PDF tetap bisa diverifikasi setelah sertifikatnya kedaluwarsa — menerbitkan sendiri sertifikat penanda tangannya, dengan OCSP dan CRL publik.

9 min read Read more →