682 字
3 分鐘
[範例] 使用 node-forge 解析憑證 | 自然人憑證開發筆記

自然人憑證的公鑰可以解析出使用者的公鑰、姓名、身分證末四碼等資訊。


Demo
程式碼
Javascript 用來讀取憑證
<script src="https://cdn.jsdelivr.net/npm/node-forge@1.3.1/dist/forge.min.js"></script>
<h1>自然人憑證 解析憑證</h1><button onclick="openPopupForm(0)">讀取根憑證</button><button onclick="openPopupForm(1)">讀取中繼憑證</button><button onclick="openPopupForm(2)">讀取簽章憑證</button><button onclick="openPopupForm(3)">讀取加密憑證</button><br /><br />憑證<br /><textarea id="certb64" rows="8" cols="65"></textarea><br><button onclick="submit()">解析</button><hr /><pre id="result"></pre>let popupForm;let timeout;let num;
function openPopupForm(certnum) { num = certnum; 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("certb64")[0].value = certs[num].certb64; }}
window.addEventListener("message", receiveMessage, false);
function submit() { const begin = "-----BEGIN CERTIFICATE-----"; const end = "-----END CERTIFICATE-----";
// 載入憑證 const certb64 = begin + document.getElementById("certb64").value + end; const cert = forge.pki.certificateFromPem(certb64);
// 建置回傳的JSON,toUtf8用於解決中文亂碼問題 const result = {}; result["subject"] = toUtf8(cert.subject); result["issuer"] = toUtf8(cert.issuer); result["validity"] = cert.validity; result["extensions"] = cert.extensions; result["serialNumber"] = cert.serialNumber; result["publicKey"] = cert.publicKey; const publicKeyPem = forge.pki.publicKeyToPem(cert.publicKey); const publicKeyB64 = publicKeyPem .replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replaceAll("\r\n", ""); result["publicKeyB64"] = publicKeyB64;
document.getElementById("result").innerHTML = JSON.stringify(result, null, 2);}
// 將object中所有value轉為utf8function toUtf8(obj) { if (typeof obj === "object" && obj !== null) { for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { obj[key] = toUtf8(obj[key]); } } return obj; } else if (typeof obj === "string") { const textDecoder = new TextDecoder("utf-8"); const byteArray = new Uint8Array([...obj].map((c) => c.charCodeAt(0))); return textDecoder.decode(byteArray); } else { return obj; }}Response 範例
以簽章憑證為例,說明如下:
- subject:本憑證資訊,個人憑證含姓名
- issuer:上級憑證資訊
- validity:有效期限
- extensions:擴充欄位
- subjectDirectoryAttributes:字串末四碼為身分證末四碼 - publicKey:公鑰的物件
- publicKeyB64:公鑰的 Base64,與 /pkcs11info?withcert=true 中的公鑰Base64 相同
{ "subject": { "attributes": [ { "type": "2.5.4.6", "value": "TW", "valueTagClass": 19, "name": "countryName", "shortName": "C" }, { "type": "2.5.4.3", "value": "周詳", "valueTagClass": 12, "name": "commonName", "shortName": "CN" }, { "type": "2.5.4.5", "value": "00000001....", "valueTagClass": 19, "name": "serialNumber" } ], "hash": "d64b521011538e55864524a...." }, "issuer": { "attributes": [ { "type": "2.5.4.6", "value": "TW", "valueTagClass": 19, "name": "countryName", "shortName": "C" }, { "type": "2.5.4.10", "value": "行政院", "valueTagClass": 12, "name": "organizationName", "shortName": "O" }, { "type": "2.5.4.11", "value": "內政部憑證管理中心", "valueTagClass": 12, "name": "organizationalUnitName", "shortName": "OU" } ], "hash": "25ab5e84667697ec05...." }, "validity": { "notBefore": "2020-11-12T01:17:56.000Z", "notAfter": "2025-11-12T15:59:59.000Z" }, "extensions": [ { "id": "2.5.29.35", "critical": false, "value": "0\u0016\u0014ú4g\t\n\"÷bH&¦EÅÃ\"¤", "name": "authorityKeyIdentifier" }, { "id": "2.5.29.14", "critical": false, "value": "\u0004\u0014sqdñ)?U\u001eo\u0000é\u0019w(¼n", "name": "subjectKeyIdentifier", "subjectKeyIdentifier": "7371649af1293f551e6f00e999197728bc87826e" }, { "id": "1.3.6.1.5.5.7.1.1", "critical": false, "value": "00G\u0006\b+\u0006\u0001\u0005\u0005\u00070\u0002;http://moica.nat.gov.tw/repository/Certs/IssuedToThisCA.p7b0A\u0006\b+\u0006\u0001\u0005\u0005\u00070\u00015http://moica.nat.gov.tw/cgi-bin/OCSP2/ocsp_server.exe", "name": "authorityInfoAccess" }, { "id": "2.5.29.15", "critical": true, "value": "\u0003\u0002\u0007", "name": "keyUsage", "digitalSignature": true, "nonRepudiation": false, "keyEncipherment": false, "dataEncipherment": false, "keyAgreement": false, "keyCertSign": false, "cRLSign": false, "encipherOnly": false, "decipherOnly": false }, { "id": "2.5.29.32", "critical": false, "value": "0\u000b0\t\u0006\u0007`ve\u0000\u0003\u0003", "name": "certificatePolicies" }, { "id": "2.5.29.9", "critical": false, "value": "0*0\u0015\u0006\u0007`v\u0001d\u0002\u00011\n\u0006\b`v\u0001d\u0003\u0001\u00010\u0011\u0006\u0007`v\u0001d\u000231\u0006\f\u00041234", "name": "subjectDirectoryAttributes" }, { "id": "2.5.29.31", "critical": false, "value": "00@ > <:http://moica.nat.gov.tw/repository/MOICA/CRL2/CRL_0028.crl0@ > <:http://moica.nat.gov.tw/repository/MOICA/CRL2/complete.crl", "name": "cRLDistributionPoints" } ], "serialNumber": "00d43a822d041...", "publicKey": { "n": { "data": [ 13863697, 47207358, ... ], "t": 79, "s": 0 }, "e": { "data": [ 65537 ], "t": 1, "s": 0 } }, "publicKeyB64": "MIIBIjANBgkqhkiG9w0BA...."}