A pragmatic look at putting an HSM into a firmware signing system: choosing a model, the key lifecycle, and why 3-of-5 cuts risk without slowing releases down.

Table of Contents

Có một thời gian tôi nhìn code signing như một bước “phụ” trong pipeline.

  • Build xong.
  • Ký.
  • Đẩy OTA.

Nhưng càng làm với firmware, tôi càng thấy “ký” không phải là một bước kỹ thuật đơn lẻ. Nó là một quyết định quản trị rủi ro.

Vì nếu private key ký firmware bị lộ, thứ bạn mất không chỉ là một artifact. Bạn mất niềm tin của cả chuỗi cung ứng.

The original question: what am I signing to protect?#

Định nghĩa nghe rất đẹp: “ký số để đảm bảo tính toàn vẹn và xác thực”.

Đọc xong vẫn có cảm giác… trừu tượng.

Đến khi đặt lại câu hỏi cho đúng:

  • Mình đang bảo vệ binary hay bảo vệ quyền phát hành?
  • Kẻ tấn công cần hack build server, hay chỉ cần lấy được private key?

Nếu private key nằm trong một file .pem trên CI runner, thì đôi khi câu trả lời đáng buồn là: không cần hack gì phức tạp, chỉ cần “lỡ” có người copy key ra khỏi đúng chỗ.

An HSM is not for making crypto faster#

Tôi từng tưởng HSM là để tăng hiệu năng crypto. Nhưng trong bối cảnh code signing, giá trị chính của HSM là: (Nếu bạn muốn hiểu sâu hơn về lớp vỏ vật lý, FIPS 140-2 và tại sao nó an toàn đến mức ‘hoang tưởng’, hãy đọc bài HSM: Pháo Đài Vật Lý Cho Những Bí Mật Số)

  • Private key được sinh ra và nằm trong phần cứng.
  • Private key không được “export” theo nghĩa thực dụng (không có file để copy).
  • Người ký phải cắm thiết bị + nhập PIN, tức là có sự hiện diện.

Nói cách khác: HSM biến “ký” từ một hàm trong code thành một hành vi có ma sát.

Ma sát này chính là thứ cứu bạn trong những ngày xui.

The decision tree: why a portable HSM (instead of a huge one)#

Khi chọn HSM cho hệ thống ký firmware, tôi thấy có ít nhất 3 hướng (mỗi hướng có cái giá riêng):

  1. HSM dạng appliance (đặt trong data center)
  • Ưu: tập trung, kiểm soát chặt.
  • Nhược: vận hành nặng; dễ trở thành “single bottleneck” cho release.
  1. Cloud HSM
  • Ưu: tích hợp tốt với cloud stack.
  • Nhược: ràng buộc cloud; câu chuyện “ai giữ key” đôi khi khó nói.
  1. HSM dạng portable cho signer
  • Ưu: chia quyền ký cho nhiều người; giảm điểm chết.
  • Nhược: phải quản lý phân phối, quy trình, audit.

Trong một triển khai điển hình, lựa chọn ở đây là một HSM dạng portable: nhỏ, có chứng nhận, hỗ trợ PKCS#11, đủ dùng cho ký Ed25519, và quan trọng là có thể phát cho từng signer.

Reality check: what do buyers (and the ops team) actually care about?#

Nếu bỏ hết jargon, tôi thấy yêu cầu thực tế hay rơi vào 3 nhóm (và nhóm nào cũng “đúng”, chỉ khác thứ tự ưu tiên):

  1. Giảm rủi ro lộ key (blast radius nhỏ)
  2. Không làm release bị kẹt (velocity)
  3. Có audit trail để giải trình (ai ký, ký cái gì, lúc nào)

Nhiều hệ thống ký số thất bại vì cố tối ưu nhóm (1) nhưng làm nát nhóm (2): mọi thứ phải qua một “ông admin giữ key”, đến lúc ông đó đi họp là release đứng hình.

The 3-of-5 signing ritual: looks like paperwork, is actually a guardrail#

Thiết kế 3-trên-5 (3-of-5) nghe có vẻ “corporate”, nhưng nó giải được một bài toán rất đời thường:

  • Không muốn 1 người có thể tự ý phát hành firmware.
  • Nhưng cũng không thể bắt đủ 5 người online cùng lúc.

Một cách nhìn đơn giản:

Build Server -> Signing Server -> (signing request) -> 5 Signers
                                       |-> thu ít nhất 3 chữ ký hợp lệ
                                       v
                                    OTA/Release

Signing flow

3-of-5 threshold

Điểm hay là bạn đang chia rủi ro theo cả hai trục:

  • Trục kỹ thuật: key nằm trong HSM, không rời khỏi thiết bị.
  • Trục tổ chức: quyền phát hành cần đồng thuận, không phụ thuộc một người.

A 3-step framework for thinking about firmware signing (pragmatic)#

Nếu phải nén mọi thứ lại để triển khai được, tôi dùng 3 bước sau:

Key lifecycle

  1. Khóa (keys)
  • Chỉ đưa private key vào nơi có kiểm soát mạnh nhất.
  • Ưu tiên “không thể copy” thay vì “khó copy”.
  1. Nghi lễ (ceremony)
  • Ai được ký? Ký cái gì? Cửa sổ ký mở bao lâu?
  • Multi-party approval (ví dụ 3-trên-5) là luật tổ chức, không phải tính năng.
  1. Bằng chứng (audit)
  • Log không phải để “đẹp”, mà để khi có sự cố bạn trả lời được: chuyện gì đã xảy ra.

Một mảnh ghép thường bị xem nhẹ là chuẩn giao tiếp giữa tool và HSM: PKCS#11. Bạn không cần nhớ hết API, chỉ cần giữ một mental model kiểu “client trao đổi với HSM” như dưới đây:

PKCS#11: signing client <-> HSM

Signing Client (app/tool)                     HSM (PKCS#11 token)
-----------------------------------------------------------------
1) C_Initialize()                     ->       token ready
2) C_OpenSession()                    ->       session handle
3) C_Login(PIN)                       ->       verify PIN / policy
4) C_FindObjects*()                   ->       key handle (non-exportable)
5) C_Sign(digest)                     ->       sign with private key
   digest ----------------------------->
   signature <--------------------------
6) C_Logout() + C_CloseSession()       ->       clear state
7) C_Finalize()                        ->       unload module

Key idea: digest goes in, signature comes out; private key never leaves HSM.

Anti-pattern: turning a private key into just another secret#

Một số phản xạ rất tự nhiên (và rất nguy hiểm):

  • Nhét private key vào CI secrets vì “tiện”.
  • Cho build server quyền ký trực tiếp vì “tự động hóa”.
  • Để một người vừa build vừa ký vì “ít người thì làm gì có separation-of-duties”.

Những thứ này đều có chung một bệnh: nó làm giảm ma sát đến mức kẻ tấn công chỉ cần chiếm một hệ thống (CI/build) là có quyền phát hành.

HSM không làm bạn miễn nhiễm. Nó chỉ giúp bạn buộc hệ thống phải trả lời câu hỏi: “Key đang ở đâu, ai đang chạm vào nó?”

Closing#

Tôi thích nhìn HSM như một cách “định hình hành vi” hơn là một món đồ crypto.

Khi bạn thiết kế ký firmware với HSM + 3-trên-5, bạn đang nói thẳng một nguyên tắc:

  • Quyền phát hành không thuộc về một script.
  • Nó thuộc về một quy trình có người chịu trách nhiệm, có đồng thuận, và có dấu vết.

Và nếu phải nhớ một câu để mang sang dự án khác: đừng tối ưu sự tiện cho người ký đến mức quên mất sự an toàn cho người dùng.

Quick definitions (so you do not get lost)#

Thuật ngữNghĩa trong bài này
OTAOver-The-Air: kênh phát hành/cập nhật firmware từ server xuống thiết bị qua mạng.
HSM (Hardware Security Module)Thiết bị phần cứng giữ private key và thực hiện thao tác ký; private key không rời khỏi thiết bị.
Code signingKý số lên firmware để thiết bị kiểm tra “ai phát hành” và “có bị sửa không”.
SignerNgười được cấp quyền ký (mỗi người giữ 1 HSM).
Signing ceremonyQuy trình/“nghi lễ” tổ chức việc ký: ai ký, ký cái gì, trong cửa sổ thời gian nào, audit ra sao.
3-of-5Cần ít nhất 3 chữ ký hợp lệ trong 5 signer để phát hành.
DigestGiá trị băm (ví dụ SHA-256) đại diện cho nội dung image; thường ký trên digest thay vì ký cả file.
Ed25519Thuật toán chữ ký (ECC) cho chữ ký 64 bytes, nhanh và gọn cho firmware.
PKCS#11Chuẩn API để app nói chuyện với HSM (open session, login, sign…).
mTLSMutual TLS: client và server đều xác thực lẫn nhau bằng certificate khi kết nối.
Signing request (trong bài này)Yêu cầu ký (payload + metadata). Tránh nhầm với Certificate Signing Request.