Skip to content

Document Signing CA

By Romi Fadli, S.Kom. 11 min read Security & Secrets
On this page
A chain of three certificates, root to issuing CA to signer, signing a PDF, while an OCSP answer and a revocation list from the issuing CA reach a validator shield alongside the document

Document Signing CA adalah certificate authority penerbit (issuing CA) berbahasa Rust yang memberi tiap orang penanda tangan dokumen PDF sertifikatnya sendiri, lalu terus menjawab pertanyaan yang diajukan setiap pembaca PDF saat membuka file bertanda tangan: apakah sertifikat ini masih sah? Ia menerbitkan sertifikat X.509 di bawah root privat, menerbitkan daftar pencabutan, menjalankan OCSP responder, dan menyerahkan key beserta rantai sertifikat tiap penanda tangan kepada service penanda tangan sebagai satu bundel PKCS#12.

Saya membangunnya karena tanda tangan hanya bernilai sebesar rantai di belakangnya. Pembaca PDF di luar organisasi, bertahun-tahun sesudah penandatanganan, harus bisa berjalan dari sertifikat penanda tangan sampai ke root, mengetahui apakah sertifikat itu dicabut, dan melakukan keduanya tanpa akun maupun rahasia. Membuat setiap field, ekstensi, dan respons tepat persis bagi pembaca-pembaca itu adalah sebagian besar pekerjaannya.

Sekilas

Bahasa & frameworkRust, dengan actix-web, sqlx di atas PostgreSQL, dan OpenSSL — lewat binding Rust-nya, dan lewat interface C-nya di tempat binding itu berhenti
ArsitekturFlat Layered
Versi2.11.2
StatusStabil, berjalan di production
BentukService HTTP mandiri: endpoint pencabutan publik untuk validator mana pun, dan API terautentikasi untuk aplikasi penanda tangan
Kode sumberPrivat
Apa module ini dan bagaimana keadaannya.

Yang dikerjakannya

A. Menerbitkan sertifikat tanda tangan

Aplikasi penanda tangan meminta sertifikat atas nama seseorang, dengan field subject yang diwajibkan organisasi. CA menyiapkan request-nya, melindungi key penanda tangan sehingga hanya penanda tangan itu yang bisa membukanya, dan menahan request itu berstatus menunggu sampai disetujui. Persetujuan menandatangani request dengan key issuing CA dan langsung mengembalikan sertifikatnya.

B. Menjawab "apakah sertifikat ini masih baik?"

OCSP responder menjawab pertanyaan pencabutan tentang sertifikat mana pun yang diterbitkan CA ini, untuk client mana pun, tanpa autentikasi: baik, dicabut beserta alasan dan waktunya, atau tak dikenal. Tiap jawaban ditandatangani sertifikat responder khusus dan membawa issuing CA, jadi validator bisa memeriksanya sendiri.

C. Menerbitkan daftar pencabutan

Untuk validator yang lebih suka daftar ketimbang bertanya, CA menerbitkan certificate revocation list di alamat yang tertulis di setiap sertifikat terbitannya, lengkap dengan nomor urut, alasan per entri, dan header cache yang memberi tahu client kapan harus mengambilnya lagi.

D. Mengirim key dan rantai sekaligus

Saat tiba waktunya menandatangani, service penanda tangan menerima sertifikat penanda tangan, sertifikat issuing CA, dan private key penanda tangan sebagai satu bundel PKCS#12 yang hanya terbuka dengan passphrase penanda tangan. PDF yang ditandatangani dengannya membawa rantai lengkap yang dibutuhkan pembaca.

E. Mengatur siapa yang boleh bertanya

Semua endpoint selain endpoint pencabutan publik mewajibkan access token bertanda tangan. User punya role, token bisa dicabut sebelum kedaluwarsa, dan setiap penerbitan, pencabutan, dan pemeriksaan pencabutan dicatat: siapa yang meminta, dari mana, dan apa yang terjadi.

Antarmuka

KemampuanAkses
Sertifikat issuing CA dalam DER, di alamat yang ditunjuk sertifikatpublik
Certificate revocation listpublik
OCSP, lewat GET dan POSTpublik
Readiness, mencakup database dan root CApublik
Meminta sertifikat; menyetujui request yang menunggutoken
Mencabut sertifikat dengan alasan RFC 5280token
Mengekspor sertifikat, rantainya, dan key-nya sebagai PKCS#12token
Login; mengelola user, role, password, dan access tokentoken, menurut role
Yang dibuka CA, dan siapa yang boleh memakainya.

Client standar mana pun bisa bertanya ke responder. Begini pemeriksaan yang biasa dijalankan validator, dengan host contoh:

bash
openssl ocsp -issuer issuing-ca.pem -cert signer.pem \
  -url http://ca.example.org/ocsp \
  -CAfile root-ca.pem -resp_text

Standar

StandarYang dijaminnya di sini
X.509 v3 dan RFC 5280sertifikat dan daftar pencabutan yang bisa dibaca validator mana pun dan ditelusuri sampai root
RFC 6960, OCSPjawaban pencabutan lewat GET atau POST, dengan nonce, dari responder yang didelegasikan
RFC 7292, PKCS#12satu bundel terenkripsi berisi key, sertifikat, dan rantai tanpa trust anchor-nya
PKCS#10certificate request diverifikasi sebelum ditandatangani
Authority Information Access dan CRL Distribution Pointssertifikat yang memberi tahu validator di mana issuer dan status pencabutannya bisa ditemukan
JSON Web Token dengan RS256access token yang ditandatangani key yang bisa dirotasi CA
W3C Trace Context dan OpenTelemetrytrace, log, dan metrics yang menyambung trace pemanggil
Standar yang dipatuhi CA, dan yang dijamin masing-masing.

Di dalamnya

CA ini mengikuti bentuk Flat Layered yang saya pakai untuk service Rust yang harus cepat jadi: route, controller, service, repository, dan helper berjajar satu tingkat, dan setiap operasi — request, approve, revoke, export, menjawab OCSP, membangun daftar pencabutan — adalah satu file di folder services. Jalur dari route ke database jadi pendek dan mudah diikuti. PostgreSQL tinggal di foldernya sendiri di dalam repositories, siap bila kelak ada storage lain. Helper yang membangun key, request, sertifikat, dan respons dijadikan stateless secara bertahap: versi kedua tiap helper berjalan berdampingan dengan yang pertama sampai hasilnya sama, baru kemudian menggantikannya, dan berakhir dengan build tanpa error maupun warning.

Keputusan rancangan

Setiap sertifikat dibentuk untuk pembaca yang akan menilainya. Sertifikat tanda tangan berversi 3 karena membawa ekstensi; satu angkatan awal yang terbit sebagai versi 1 dengan ekstensi versi 3 mengajari saya untuk menetapkan versinya secara eksplisit. Key usage-nya critical dan terbatas pada digital signature dan non-repudiation, extended key usage-nya menyebut document signing, dan authority key identifier-nya hanya membawa key identifier, karena bentuk panjangnya menunjuk root lewat nama dan membingungkan validator. Field subject, urutannya, dan aturannya — panjang pasti, format e-mail, minimum dan maksimum — tinggal di konfigurasi, begitu pula pilihan apakah alamat e-mail ikut masuk subject alternative name. Profil organisasi baru tak butuh kode baru. Sertifikat berlaku tiga tahun di bawah issuing CA yang berlaku sepuluh tahun dan root yang berlaku dua puluh tahun, dengan path length yang mencegah rantai bertambah panjang.

Kepercayaan berawal dari satu root, dan issuing CA membuktikan dirinya terhadap root itu. Sebelum service menerima request, sertifikat issuing CA diverifikasi terhadap root itu, dan setiap keraguan berakhir dengan penolakan.

Menandatangani tak boleh menuntut penanda tangan memasang apa pun. Tepat saat penandatanganan, service penanda tangan menerima bundel PKCS#12 siap pakai yang hanya bisa dibuka passphrase milik penanda tangan. Request diverifikasi sebelum ditandatangani, persetujuan berlangsung dalam satu transaksi dengan satu timestamp untuk sertifikat dan catatannya, dan satu request hanya bisa diterbitkan sekali.

Bundel membawa rantai, dan tak lebih. Ekspor PKCS#12 berisi sertifikat penanda tangan dan issuing CA, tapi tidak root: root adalah trust anchor yang harus sudah dipegang pembaca, bukan barang yang diserahkan lewat file. Sebelum perubahan ini, service penanda tangan melihat rantai sepanjang satu lalu mencoba — dan gagal — mengambil issuer yang hilang sendiri.

Pemeriksaan pencabutan bersifat publik, karena validator adalah orang asing. Pembaca PDF yang memeriksa tanda tangan milik siapa pun yang menerima dokumen, bukan milik organisasi yang menandatanganinya. Karena itu OCSP responder dan daftar pencabutan menjawab siapa saja, lewat GET maupun POST. Keduanya sengaja diletakkan di luar scope terlindung: pernah lapisan autentikasi memblokir responder, dan perbaikan yang memisahkan keduanya sempat membuat semua route lain menjawab 404, sampai kedua endpoint publik itu didaftarkan di tingkat teratas aplikasi.

Jawaban OCSP harus bisa diperiksa sendiri dan tahan terhadap jam yang tak sempurna. Jawaban ditandatangani sertifikat responder tersendiri, bertanda critical untuk OCSP signing, dan CA memperbaruinya secara otomatis. Tiap jawaban membawa issuing CA, memantulkan nonce client, dan mencocokkan issuer memakai algoritma yang sama dengan client. Awal masa berlaku jawaban dimundurkan sedikit, supaya client yang jamnya sedikit terlambat tak membuangnya sebagai "belum berlaku". Request yang cacat atau gagal menerima status error OCSP yang ditandatangani, bukan HTTP 500, karena itulah yang dipahami validator; jawaban tanpa nonce membawa header cache yang kedaluwarsa pada sembilan puluh persen masa berlakunya.

Di tempat library Rust berhenti, interface C melanjutkan. Binding OpenSSL untuk Rust tak bisa membangun daftar pencabutan maupun respons OCSP, jadi CA memanggil interface C OpenSSL secara langsung, lewat binding yang dibuat hanya untuk daftar fungsi yang sempit. Daftar pencabutan berversi 2, versi yang dipakai pembaca PDF Adobe; ia membawa nomor urut, authority key identifier, dan alasan untuk tiap entri. Daftar itu hanya disajikan di alamat yang disebut sertifikat: endpoint itu pernah rusak tanpa ada yang menyadari, dan saat memperbaikinya saya menghapus path terpisah yang dulu membangun daftar, jadi hanya ada satu alamat untuk diperiksa dan itulah alamat yang dipakai validator.

Alamat pencabutan memakai HTTP biasa. Alamat yang ditulis di setiap sertifikat — tempat issuer, daftar pencabutan, dan responder ditemukan — memakai HTTP, bukan HTTPS: memeriksa pencabutan lewat TLS berarti lebih dulu memeriksa pencabutan sertifikat TLS-nya, lingkaran yang dihindari validator. Sertifikat issuing CA sendiri disajikan dalam DER di alamatnya, dan sertifikat responder hanya menunjuk issuer-nya, tak pernah menunjuk dirinya sendiri. Saat satu sertifikat lama ternyata membawa alamat HTTPS, penyebabnya konfigurasi yang usang, bukan kode; sertifikat tak bisa disunting, jadi jawabannya menerbitkan ulang.

CA mengautentikasi pemanggilnya sendiri. Aplikasi penanda tangan memanggil CA secara langsung, jadi akses memakai token bertanda tangan. Token membawa key identifier, sehingga merotasi key penanda tangan token tak membatalkan token yang sudah terbit, dan token mana pun bisa dicabut sebelum kedaluwarsa; user bisa memegang beberapa role di tingkat berbeda, dan password hanya disimpan dalam bentuk hash.

Setiap keputusan tentang sertifikat meninggalkan bukti. Telemetry pindah dari menulis langsung ke Elasticsearch menjadi OpenTelemetry lewat collector, sambil melanjutkan trace pemanggil. Penerbitan, pencabutan, pemeriksaan OCSP, dan daftar pencabutan menghasilkan event audit yang menyebut siapa yang bertindak, dari mana, atas apa, dan dengan hasil apa. Nilai sensitif diredaksi dari log, sementara identitas orang yang bertindak dijaga secara eksplisit — satu field yang tak boleh hilang dari audit tanda tangan. Metrics memakai delta temporality, yang diwajibkan exporter Elasticsearch milik collector; alamat client diambil dari header forwarded hanya bila datang dari trusted proxy, dengan rantai mentahnya disimpan sebagai bukti.

Skema ikut bersama binary yang membutuhkannya. Migration menjadi bagian dari image dan dijalankan oleh langkah deployment terpisah. Dulu migration hanya berjalan saat database kosong pertama kali dibuat, sehingga perubahan berikutnya tak pernah sampai ke staging maupun production. Menyimpannya di repository lain saya tolak, karena lupa menyalinnya akan gagal tanpa suara. Readiness baru melapor sehat bila database dan root CA sama-sama menjawab, dan service berjalan sebagai user non-root.

Spesifikasi

MasukanRequest, persetujuan, pencabutan, dan ekspor sertifikat dari aplikasi penanda tangan; pertanyaan OCSP dan unduhan daftar dari validator mana pun
HasilSertifikat X.509 v3, bundel PKCS#12, jawaban OCSP bertanda tangan, dan daftar pencabutan versi 2
KeyRSA 4096 untuk penanda tangan, responder, dan CA; SHA-256 secara default
Masa berlakuPenanda tangan tiga tahun; responder diperbarui otomatis; jawaban OCSP dan daftar pencabutan satu hari
PenyimpananPostgreSQL, dengan migration yang dikirim di dalam image
Diverifikasi denganTool OCSP dan CRL milik OpenSSL serta pembaca PDF yang memvalidasi tanda tangannya
ObservabilityTrace, log, metrics, dan event audit OpenTelemetry lewat OTLP
Berjalan sebagaiImage container, sebagai user non-root, dengan konfigurasi di-mount dari volume
Yang diterima, dikembalikan, dan dibutuhkan CA.

Terkait

Toolkit yang menjalankan migration CA saat satu rilis sampai ke production.

Ke mana event audit, trace, dan metrics CA pergi setelah meninggalkan service.

Istilah

Certificate authority
Service yang menjamin satu public key dengan menandatangani sertifikat yang mengikat key itu pada satu nama.
Issuing CA
Certificate authority yang sertifikatnya ditandatangani root, dan yang menandatangani sertifikat yang benar-benar dipakai orang.
OCSP
Online Certificate Status Protocol: client menanyakan apakah satu sertifikat masih sah dan menerima jawaban bertanda tangan.
Certificate revocation list
Daftar bertanda tangan berisi semua sertifikat yang telah dicabut CA, diterbitkan di alamat yang tertulis di sertifikatnya.
PKCS#12
Format file yang membundel private key dengan sertifikat dan rantainya, dilindungi password.
Trust anchor
Sertifikat root yang sudah dipercaya validator, tempat setiap rantai yang diperiksanya harus berakhir.

Technologies covered

  • Rust
  • PostgreSQL
  • OpenTelemetry
  • OCSP
  • X.509

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 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 signed PDF with a QR stamp, wrapped in four nested frames for the signature, its timestamp, the embedded validation data, and the archive timestamp

Service Python yang menandatangani PDF sampai PAdES B-LTA dengan stempel yang terlihat — menanamkan stempel waktu, sertifikat, dan bukti pencabutan, lalu stempel waktu arsip — supaya tanda tangan tetap bisa diverifikasi lama setelah sertifikatnya kedaluwarsa, dan memverifikasi PDF bertanda tangan.

10 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 →
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 signed PDF with a QR stamp, wrapped in four nested frames for the signature, its timestamp, the embedded validation data, and the archive timestamp

Service Python yang menandatangani PDF sampai PAdES B-LTA dengan stempel yang terlihat — menanamkan stempel waktu, sertifikat, dan bukti pencabutan, lalu stempel waktu arsip — supaya tanda tangan tetap bisa diverifikasi lama setelah sertifikatnya kedaluwarsa, dan memverifikasi PDF bertanda tangan.

10 min read Read more →