537 字
3 分鐘
[範例] node-forge 驗證憑證鏈 | 自然人憑證開發筆記

前文有介紹到,自然人憑證卡裡面有四張憑證,包含政府根憑證、內政部中繼憑證、兩張個人終端憑證(簽章、加密),本文將說明如何透過後端對終端憑證做憑證鏈驗證。

Demo
前端程式碼
前文學習到如何讀取自然人憑證裡面的四張憑證,範例為讀取憑證後,按下驗證按鈕進行驗證憑證鏈。
<h1>自然人憑證 憑證鏈驗證</h1><input type="button" value="讀取簽章憑證" onclick="getCert(true)" /><input type="button" value="讀取加密憑證" onclick="getCert(false)" /><form action="https://cert.modatw.workers.dev/api/certChainVerify" method="post"> 根憑證<br> <textarea name="cert1b64" rows="8" cols="65"></textarea><br> 中繼憑證<br> <textarea name="cert2b64" rows="8" cols="65"></textarea><br> 終端憑證<br> <textarea name="cert3b64" rows="8" cols="65"></textarea><br> <input value="驗證" type="submit"></form><script> let popupForm; let timeout; let cert;
function getCert(c) { cert = c; popupForm = window.open( "http://localhost:61161/popupForm", "popupForm", "height=200, width=200, left=100, top=20" ); timeout = setTimeout(() => { popupForm.close(); alert("尚未安裝元件"); }, 5000); }
function receiveMessage(event) { if (event.origin !== "http://localhost:61161") return;
let ret = JSON.parse(event.data); if (ret.func === "getTbs") { clearTimeout(timeout); const tbsData = { func: "GetUserCert" }; popupForm.postMessage(JSON.stringify(tbsData), "*"); } else { const data = JSON.parse(event.data); const certs = data.slots[0].token.certs; document.getElementsByName("cert1b64")[0].value = certs[0].certb64; document.getElementsByName("cert2b64")[0].value = certs[1].certb64; document.getElementsByName("cert3b64")[0].value = cert ? certs[2].certb64 : certs[3].certb64; } }
window.addEventListener("message", receiveMessage, false);</script>後端程式碼
後端接收到前端傳過來的三張憑證,並進行憑證鏈驗證,這裡以 Cloudflare Workers 搭配 node-forge 套件來實作。
// 本範例環境為 Cloudflare Workers// 程式碼適用於 NodeJS,需安裝 node-forge
// 以下為 Cloudflare Workers 可用的 node-forge// https://gist.github.com/chouhsiang/2dad8070e517b61cec3d175b1832c4beimport { forge } from "./node-forge.js";
export default { async fetch(request, env, ctx) { try { const { pathname } = new URL(request.url); if (pathname == "/api/certChainVerify" && request.method == "POST") { return await certChainVerify(request); } return new Response(""); } catch (e) { return new Response(e); } },};
async function certChainVerify(request) { const formData = await request.formData(); const begin = "-----BEGIN CERTIFICATE-----"; const end = "-----END CERTIFICATE-----";
// 將憑證轉為 PEM 格式 const rootCACert = begin + formData.get("cert1b64") + end; const intermediateCert = begin + formData.get("cert2b64") + end; const endEntityCert = begin + formData.get("cert3b64") + end;
// 解析 PEM const rootCACertificate = forge.pki.certificateFromPem(rootCACert); const intermediateCertificate = forge.pki.certificateFromPem(intermediateCert); const endEntityCertificate = forge.pki.certificateFromPem(endEntityCert);
// 建立 CA 儲存庫,加入根憑證、中繼憑證 const caStore = forge.pki.createCaStore([rootCACertificate, intermediateCertificate]);
// 驗證憑證 try { forge.pki.verifyCertificateChain(caStore, [endEntityCertificate]); return new Response("成功"); } catch (e) { return new Response("失敗," + JSON.stringify(e)); }}