3 poin oleh GN⁺ 2025-05-24 | 1 komentar | Bagikan ke WhatsApp
  • Penulis selama bertahun-tahun merasa enggan terhadap protokol ACME karena kompleksitas dan risiko implementasinya
  • Klien ACME yang sudah ada banyak yang memiliki kode yang berisiko dari sisi keamanan atau sulit dipahami, sehingga enggan dijalankan sendiri
  • Namun, karena kualitas registrar domain Gandi menurun dan harganya naik, ia akhirnya mengimplementasikan alat pembaruan sertifikat sendiri
  • Setelah banyak trial and error, ia berhasil menyelesaikan alat untuk menerbitkan sertifikat sendiri melalui Let's Encrypt
  • Pada paruh akhir tulisan, dijelaskan secara rinci proses kerja nyata protokol ACME serta detail implementasi tingkat rendah seperti JSON, base64, tanda tangan, dan lain-lain

Why I no longer have an old-school cert on my https site

Latar belakang dan pemicu

  • Pada awal 2023, ia menjelaskan alasan tetap mempertahankan sertifikat gaya lama, tetapi pada 2025 ia membagikan alasan akhirnya meninggalkan pendekatan tersebut
  • Penolakan terhadap protokol ACME sudah ada sejak 2018, dan teknologi web yang rumit serta skema encoding yang sulit dipahami menjadi hambatan besar
  • Sebagian besar klien ACME memiliki kode yang sulit dipercaya, dan dinilai terlalu berisiko untuk dijalankan dengan hak root
  • Setelah Gandi diakuisisi oleh private equity, kualitasnya menurun dan harga naik, sehingga tidak ada lagi alasan untuk mempertahankan sertifikat lama

Awal implementasi mandiri

  • Tanpa memakai alat yang sudah ada, ia mulai mengimplementasikan sendiri fungsi-fungsi utilitas kecil satu per satu
  • Ia memulai dari membungkus pustaka JSON C bernama jansson agar bisa digunakan di C++
  • Ia meninjau berbagai pustaka untuk membuat JWK (struktur key), tetapi kebanyakan tidak membantu, sehingga memutuskan untuk membuatnya sendiri
  • Di tengah jalan, ia beberapa kali berhenti lalu memulai lagi, sambil secara bertahap menghubungkan komponen-komponen kecil tersebut

Lingkungan pengujian dan penerapan nyata

  • Agar tidak langsung menyentuh server produksi Let's Encrypt, ia menggunakan server ACME pengujian bernama "pebble" di lingkungan terpisah

  • Setelah banyak kegagalan, ia menyelesaikan alat awal yang menerima CSR lalu menerbitkan sertifikat, dan

    • berhasil diuji di server staging Let's Encrypt
    • berhasil juga di lingkungan produksi
    • sudah diterapkan ke situs web nyata

Penjelasan rinci protokol ACME

  • Membuat key RSA dan CSR (Certificate Signing Request) yang mencakup CN serta SAN
  • Mem-parsing JSON dari URL direktori ACME untuk mengekstrak endpoint seperti newNonce, newAccount, newOrder
  • Dari private key, mengekstrak modulus dan public exponent, lalu mengubahnya ke encoding base64url yang sesuai untuk web
  • Setelah membuat JWK, melakukan penandatanganan RSA SHA256 bersama payload JSON
  • Mengambil Nonce melalui permintaan HTTP HEAD, lalu mengirim permintaan POST yang telah ditandatangani untuk membuat akun
  • Header respons Location digunakan bukan sebagai redirect sungguhan, melainkan sebagai URL pengenal akun

Kompleksitas protokol ACME

  • Meskipun hanya untuk penerbitan sertifikat sederhana, tetap melibatkan
    • hash SHA256, base64web, struktur JSON di dalam JSON, tanda tangan RSA
    • permintaan HEAD, identifikasi akun melalui header Location, kebutuhan Nonce sekali pakai, dan lain-lain
  • Disebutkan bahwa tahap pemesanan sertifikat, pembuktian kepemilikan domain (seperti record TXT), dan penyelesaian validasi bahkan belum sempat dibahas
  • Beberapa klien ternyata tetap berjalan meski implementasi encoding publicExponent-nya salah, sehingga ia juga menyoroti longgarnya penerapan standar

Kesimpulan

  • ACME sangat kompleks, dan mengimplementasikannya sendiri menuntut banyak trial and error serta usaha besar
  • Meski begitu, ia membagikan bahwa dirinya berhasil meninggalkan sertifikat gaya lama dan beralih ke pendekatan otomatis penuh
  • Ia juga menambahkan candaan bahwa kompleksitas ini mungkin saja dirancang untuk menjamin pekerjaan seseorang

1 komentar

 
GN⁺ 2025-05-24
Komentar Hacker News
  • Saya adalah tech lead di tim SRE/infra Let’s Encrypt, jadi saya termasuk orang yang banyak memikirkan masalah seperti ini
    JSON Web Signature memang format yang sangat merepotkan, dan ACME API juga sangat bersikeras untuk benar-benar RESTful
    Kalau saya yang merancangnya sendiri, saya tidak akan membuatnya seperti ini
    Saya rasa latar belakang terbentuknya struktur seperti ini adalah keinginan IETF untuk banyak memanfaatkan standar IETF, ditambah desain ala komite
    Dengan beberapa library untuk JSON, JWS, dan HTTP, situasinya memang jadi jauh lebih baik, tetapi terutama di C, bahkan library-library itu sendiri tidak mudah digunakan
    Bahasa RFC sendiri juga rumit dan sering merujuk ke dokumen lain, jadi kami sedang membuat klien interaktif dan dokumentasi terpisah untuk membantu hal ini

    • Saya kurang paham dengan pernyataan bahwa JSON Web Signature adalah format yang merepotkan
      Dari sudut pandang saya yang banyak menangani hal-hal kompleks seperti ASN.1, Kerberos, dan PKI, saya tidak merasa JWS adalah format yang sesulit itu
      Bahkan jika menulisnya langsung dalam kode, menurut saya itu masih jauh lebih mudah daripada S/MIME, CMS, atau Kerberos
      Perlu penjelasan lebih lanjut di bagian mana JWS itu dianggap ‘merepotkan’
      Kalau masalahnya JWT, saya justru merasa inti persoalannya adalah belum ada ketentuan yang jelas secara standar tentang bagaimana user agent HTTP harus menerima atau meminta JWT

    • Saya melihat ada orang yang berkata “kalau mau menerbitkan lebih dari 3 sertifikat harus bayar”, tetapi selama 5 tahun terakhir saya memakainya, saya tidak pernah sekali pun menerima tagihan, jadi ini tampaknya sekadar salah paham atau informasi yang keliru

  • Saat membahas bagian yang memakai “e=AQAB” alih-alih “e=65537”, dijelaskan bahwa penyebabnya adalah sifat JSON yang tidak bisa menangani angka dengan baik
    Jika nilai yang sangat besar seperti 4723476276172647362476274672164762476438 diberikan ke parser JSON, kebanyakan parser JSON akan diam-diam memotongnya menjadi integer 64-bit atau float, atau kalau beruntung malah mengeluarkan error
    Bahasa seperti Common Lisp mungkin bisa menanganinya dengan baik, tetapi pada praktiknya tidak banyak orang yang mengembangkan di lingkungan seperti itu
    Jadi untuk mengirim angka besar secara andal di JSON, mengubahnya menjadi array byte lalu base64 justru terasa lebih masuk akal
    Walau sekilas terlihat tidak masalah, hal ini menjadi sumber berbagai isu keamanan, jadi menurut saya masuk akal jika semua angka dalam protokol ditangani dengan cara seperti ini
    Hanya saja, kekurangannya adalah keterbacaan JSON yang ramah manusia jadi hilang, dan secara pribadi saya merasa S-Expression yang distandardisasi akan menjadi pilihan yang jauh lebih baik
    Tapi dunia memilih JSON

    • Kalau tidak mengerti kenapa dunia memilih JSON, saya rasa itu sama saja dengan sengaja mengabaikannya
      JSON memungkinkan kebanyakan data ditulis, diedit, dan dibaca manusia dengan mudah
      Sebaliknya, Canonical S-Expression mengharuskan informasi panjang ditambahkan di depan setiap elemen, jadi sangat merepotkan jika dikerjakan manual
      Untuk menulis S-Expression, kita harus menghitung karakter satu per satu dan mengubah prefix-nya juga, jadi sangat menyebalkan
      Bertentangan dengan dugaan, justru kemudahan penulisan dan pengeditan manual seperti inilah yang membuat JSON bertahan
      Sebagai catatan, parser JSON di Ruby menangani angka besar dengan baik

    • Saya pernah dibuat pusing oleh bug di aplikasi C# ketika serializer JSON mengeluarkan BigInt sebagai angka, lalu JS menerimanya dan salah menafsirkannya secara diam-diam
      Saya masih heran bahwa overflow adalah perilaku standar alih-alih error
      Sejak itu, saya membiasakan diri untuk selalu menangani angka yang lebih besar dari 32-bit sebagai string

    • Perbandingan antara {"e":"AQAB"} dan {"e":65537} memang ada benarnya, tetapi kalau dibandingkan dengan {"e":"65537"}, hasil penanganannya juga sama di semua parser JSON
      Entah angka atau string, keduanya tetap dikonversi dengan jelas
      Tentu saja kalau nilainya terlalu besar sampai tidak muat sebagai double, itu sendiri adalah masalah bahasa atau parser, tetapi menurut saya itu terpisah dari cara representasinya

    • Saya rasa masalah JSON bukan pada formatnya sendiri, melainkan karena parser-nya sejak awal dibuat untuk pemetaan tipe JS
      Beberapa parser mungkin bisa menanganinya dengan baik, tetapi kalau begitu portabilitas JSON justru hilang
      Mengubahnya ke Base64 pun menimbulkan masalah yang sama (karena tidak sesuai standar)
      Parsing kustom dengan replacer dan reviver memang mungkin, tetapi tidak semua lingkungan menjamin fitur itu ada
      Pada akhirnya, asumsi bahwa JSON bisa diinterpretasikan dengan parser standar itulah akar kesalahannya
      Kalau ini disebut format lain, bukan JSON, mungkin masalah seperti ini akan berkurang, tetapi orang-orang tetap saja akan cenderung memasukkannya ke parser begitu melihat bentuknya seperti JSON

    • Bahasa Go memiliki tipe json.Number yang memungkinkan angka didekodekan sebagai string tanpa kehilangan informasi
      Saya juga memperkenalkan salah satu tipe decimal presisi arbitrer yang hampir jadi ‘favorit’ saya https://github.com/ncruces/decimal?tab=readme-ov-file#decimal-arithmetic
      Setengah bercanda, saya tidak terlalu paham kenapa dalam kasus ini S-Expression dianggap lebih baik
      Bahkan di antara LISP pun ada yang tidak mendukung aritmetika presisi arbitrer

  • Saya heran kenapa penulis begitu kritis terhadap ACME dan berbagai kliennya
    Rasanya ini bukan sekadar soal kemampuan memakai alat, jadi saya menduga ada semacam antipati terhadap konsep ACME itu sendiri atau seluruh ekosistem alat di sekitarnya
    Sejak 2019 kami juga menerapkannya di beberapa situs berbasis LE, dan selama itu sudah mencoba berbagai klien ACME
    Misalnya Crypt-LE cukup cocok untuk kebutuhan kami, dan saat mencoba integrasi dengan Sectigo ACME, le64 terasa kurang sehingga kami mencoba certbot, lego, posh-acme, dan lain-lain
    Pada akhirnya kami memakai certbot setelah memperbaiki masalah lingkungan GHA, dan posh-acme juga bagus
    Setelah dibaca lagi, nada tajam penulis tampaknya bukan ditujukan ke ACME atau kliennya, melainkan ke spesifikasinya sendiri
    Kesimpulannya, ide ACME bagus, tetapi implementasi dan penerapan nyatanya mengecewakan

    • Saya rasa pandangan saya mirip dengan penulis
      Saya mengutip ucapan penulis: ‘banyak klien yang ada itu kodenya berbahaya, dan saya tidak cukup percaya untuk menjalankannya sebagai root di server saya’
      Untuk pekerjaan yang sensitif terhadap keamanan, menurut saya sikap hati-hati seperti ini sangat masuk akal

    • Untuk memberi konteks kepada orang yang kesulitan memahami nada tulisan aslinya, diperkenalkan tautan ke postingan lama

    • Ada banyak orang yang memang tidak suka menjalankan sesuatu di server yang mereka sendiri tidak pahami, dan saya juga bisa memahami pemikiran itu
      Tetapi bidang keamanan pada dasarnya adalah permainan kucing dan tikus, jadi sifatnya memang terus berubah dan pada akhirnya kita harus mengikutinya
      Untungnya, ACME memberi kebebasan untuk membuat klien sendiri
      Tidak wajib memakai certbot, dan ini juga bukan struktur seperti TPM yang mengunci sumber daya kita

  • Kalau ingin mengimplementasikan klien ACME dari nol, pengalaman saya menunjukkan bahwa membaca RFC (beserta dokumen terkait seperti JOSE) ternyata lebih mudah dari yang dibayangkan
    Saya juga pernah mengimplementasikannya sendiri dan menulis ringkasan untuk memahami alur ACME v2, lalu membagikannya di https://www.arnavion.dev/blog/2019-06-01-how-does-acme-v2-work/
    Tulisan ringkasan ini memang tidak menggantikan RFC resmi, tetapi bagus dijadikan referensi seperti flowchart dan indeks berdasarkan jenis pendekatan

    • Saya bahkan pernah mengimplementasikan klien ACME sebagai proyek akhir kelas keamanan MIT https://css.csail.mit.edu/6.858/2023/labs/lab5.html

    • Ada sindiran terhadap kenyataan aneh bahwa alih-alih membaca manual satu per satu, menulis postingan panjang di Hacker News dalam bahasa Inggris yang menjelaskan seluruh proses justru bisa menghasilkan lebih banyak internet point

  • Penulis mengucapkan terima kasih karena ada yang menyoroti makin kompleksnya protokol infrastruktur web
    Standar-standar seperti ini memang bukan cuma membebani developer yang harus sekadar memakai tool atau klien, tetapi juga bekerja seperti ‘hambatan regulatif’ yang pada akhirnya membuat hanya perusahaan besar yang sudah mapan mampu memenuhi syarat untuk mengoperasikan internet
    ACME saja mungkin belum menjadi hambatan masuk yang tak terlewati, tetapi semua ini menumpuk dan akhirnya menjadi tembok

    • Disampaikan optimisme bahwa protokol-protokol ini semuanya memiliki implementasi open source, dan berkat perkembangan AI, hambatan seperti ini akan makin rendah
  • OpenBSD memiliki klien ACME yang sangat sederhana dan ringan yang sudah disertakan dalam base OS
    Katanya ini dibuat baru karena alternatif yang ada terlalu berat dan bertentangan dengan filosofi Unix
    Agak disayangkan penulis tampaknya tidak mempertimbangkan opsi ini
    Mungkin dengan sedikit usaha, ini juga bisa di-port ke OS lain

    • Saya justru merasa klien OpenBSD ini adalah contoh bahwa filosofi OpenBSD tidak benar-benar memahami kenapa keamanan bisa serumit ini
      Klien ini dipasang dan dipakai pada mesin yang bersangkutan, lalu dibuat dengan struktur terpisah agar tiap komponen tidak saling memengaruhi
      Tetapi protokol ACME sendiri sebenarnya memungkinkan pemisahan total (air-gapping), sehingga web server, peminta sertifikat, dan server DNS bisa saja berada di lingkungan yang berbeda
      Kalau tidak memakai klien terintegrasi OpenBSD, mungkin memang lebih rumit, tetapi dari sudut prinsip desain keamanan, pendekatan itu menurut saya lebih unggul
      ‘Cukup pasang OpenBSD dan selesai’ hanyalah cara yang lebih mudah

    • uacme (https://github.com/ndilieto/uacme) juga diperkenalkan
      Ini adalah kode C yang ringan, dan setelah terus-terusan bermasalah dengan klien Python LE karena isu battery, saya memakainya sebagai alternatif dengan stabil

    • Saya sendiri memakai klien ACME OpenBSD secara langsung, dan pengalaman saya itu berjalan sangat baik

  • Rekomendasi untuk membuat private key RSA 4096-bit justru hanya menimbulkan masalah penurunan kecepatan bagi pengunjung, sementara keamanan riilnya tetap setara level 2048-bit
    Ditekankan bahwa memakai sertifikat leaf RSA 2048-bit lebih baik

    • Ditanyakan apakah 4096 bit tidak lebih kuat terhadap passive capture/dekripsi di masa depan
      Juga ada rasa penasaran apakah keamanan sertifikat intermediate turut terpengaruh oleh serangan asinkron semacam itu

    • Karena web host hanya mendukung kunci RSA, saya sengaja memakai RSA 4096-bit agar mereka terdorong untuk lebih cepat mendukung kunci EC

  • Mencoba hal seperti ini sendiri memang bisa meningkatkan kemampuan, tetapi nada tulisan penulis tampak seperti sedang melampiaskan kekesalan terhadap protokol atau proses penyiapan Let’s Encrypt
    Dengan library ACME yang ringan (https://github.com/jmccl/acme-lw dan sebagainya) seharusnya otomatisasi pun sudah cukup memungkinkan, jadi saya penasaran kenapa harus dibuat sesulit ini

    • SSL benar-benar adalah ‘kumpulan kekacauan panas yang sudah membatu’
      Masalah flat/bitfield semuanya merupakan warisan sejarah ASN.1/X.509, kompleksitas matematisnya sangat parah, dan semua library serta software masih terikat pada keterbatasan teknologi era 80-an
      Saat adopsi LetsEncrypt atau kemunculan HTTP/2 sebenarnya ada peluang terakhir untuk membereskan kekacauan ini, tetapi pada kenyataannya ACME CA cukup dirangkai dari shell script, OpenSSL, dan alkohol, ditambah masalah kompatibilitas dengan software lama, sehingga lompatan besar itu tidak pernah terjadi
  • Dibagikan pengalaman bahwa tekanan untuk beralih ke HTTPS terus makin kuat
    Misalnya, tautan HTTP di WhatsApp sekarang bahkan tidak bisa lagi dibuka

    • Disarankan bahwa dengan memakai proxy dan caching, beban trafik bisa dikurangi, dan itu adalah cara yang baik untuk server kecil

    • Ditekankan bahwa sekompleks apa pun ACME, itu tetap jauh lebih baik daripada tidak mendukung TLS sama sekali

  • “Kunci RSA, digest SHA256, tanda tangan RSA, base64 yang sebenarnya bukan base64, penggabungan string, JSON di dalam JSON, memakai header Location sebagai identifier alih-alih redirect 301, request HEAD hanya untuk satu nilai header, perlu request terpisah untuk nonce di setiap request, dan seterusnya”
    “Masih ada langkah yang lebih rumit lagi, seperti membuat order sertifikat, menangani otorisasi dan challenge, key thumbprint, menyusun record TXT, dan lain-lain”
    Ini benar-benar kompleksitas yang sulit dipercaya, dan disampaikan pesan dukungan serta terima kasih karena sudah membagikan rangkumannya