2027 字
10 分鐘
[HiPKI Local Server] /selfTest.htm 檢測 IC 卡功能 | 自然人憑證開發筆記

/selfTest.htm
想測試自然人憑證功能可以 http://127.0.0.1:61161/selfTest.htm,可以看到卡片內有兩組憑證,分別用於簽章、加密,另外還有卡號、姓名、序號等資訊。

Request
GET http://127.0.0.1:61161/selfTest.htmResponse
<!DOCTYPE html><html> <meta http-equiv="X-UA-Compatible" content="IE=EDGE" charset="utf-8" />
<head> <title>IC卡功能檢測</title> <script type="text/javascript"> var passString = "V"; var failString = "X"; (function (window) { { var unknown = "-";
var nVer = navigator.appVersion; var nAgt = navigator.userAgent; var version = "" + parseFloat(navigator.appVersion); var majorVersion = parseInt(navigator.appVersion, 10); var nameOffset, verOffset, ix;
// trim the version string if ((ix = version.indexOf(";")) != -1) version = version.substring(0, ix); if ((ix = version.indexOf(" ")) != -1) version = version.substring(0, ix); if ((ix = version.indexOf(")")) != -1) version = version.substring(0, ix);
majorVersion = parseInt("" + version, 10); if (isNaN(majorVersion)) { version = "" + parseFloat(navigator.appVersion); majorVersion = parseInt(navigator.appVersion, 10); }
// mobile version var mobile = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(nVer);
// system var os = unknown; var clientStrings = [ { s: "Windows 10/11", r: /(Windows 10.0|Windows NT 10.0)/ }, { s: "Windows 8.1", r: /(Windows 8.1|Windows NT 6.3)/ }, { s: "Windows 8", r: /(Windows 8|Windows NT 6.2)/ }, { s: "Windows 7", r: /(Windows 7|Windows NT 6.1)/ }, { s: "Windows Vista/Windows Server 2008", r: /Windows NT 6.0/ }, { s: "Windows Server 2003", r: /Windows NT 5.2/ }, { s: "Windows XP", r: /(Windows NT 5.1|Windows XP)/ }, { s: "Windows 2000", r: /(Windows NT 5.0|Windows 2000)/ }, { s: "Windows ME", r: /(Win 9x 4.90|Windows ME)/ }, { s: "Windows 98", r: /(Windows 98|Win98)/ }, { s: "Windows 95", r: /(Windows 95|Win95|Windows_95)/ }, { s: "Windows NT 4.0", r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/, }, { s: "Windows CE", r: /Windows CE/ }, { s: "Windows 3.11", r: /Win16/ }, { s: "Android", r: /Android/ }, { s: "Open BSD", r: /OpenBSD/ }, { s: "Sun OS", r: /SunOS/ }, { s: "Linux", r: /(Linux|X11)/ }, { s: "iOS", r: /(iPhone|iPad|iPod)/ }, { s: "Mac OS X", r: /Mac OS X/ }, { s: "Mac OS", r: /(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ }, { s: "QNX", r: /QNX/ }, { s: "UNIX", r: /UNIX/ }, { s: "BeOS", r: /BeOS/ }, { s: "OS/2", r: /OS\/2/ }, { s: "Search Bot", r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/, }, ]; for (var id in clientStrings) { var cs = clientStrings[id]; if (cs.r.test(nAgt)) { os = cs.s; break; } }
var osVersion = unknown;
if (/Windows/.test(os)) { osVersion = /Windows (.*)/.exec(os)[1]; os = "Windows"; }
switch (os) { case "Mac OS X": osVersion = /Mac OS X (10[\.\_\d]+)/.exec(nAgt)[1]; break;
case "Android": osVersion = /Android ([\.\_\d]+)/.exec(nAgt)[1]; break;
case "iOS": osVersion = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer); osVersion = osVersion[1] + "." + osVersion[2] + "." + (osVersion[3] | 0); break; } }
osArch = get_bits_system_architecture();
if (mobile == true) mobile = " (Mobile) "; else mobile = "";
window.jscd = { os: os, osVersion: osVersion, osArch: osArch, mobile: mobile, };
/* //Detect Win 11 (replace info) //IE cannot be applied var verOffset; if ( (os == "Windows") && (osVersion == '10/11') && ((verOffset=nAgt.indexOf("Chrome"))!=-1) ){ navigator.userAgentData.getHighEntropyValues(["platformVersion"]) .then(ua => { const majorPlatformVersion = parseInt(ua.platformVersion.split('.')[0]);
if (majorPlatformVersion >= 13) { osVersion = "11";
//replace info window.jscd = { os: os, osVersion: osVersion, osArch: osArch, mobile: mobile, };
} }); } */ })(this);
function checkBrowser() { var nVer = navigator.appVersion; var nAgt = navigator.userAgent; var browserName = navigator.appName; var fullVersion = "" + parseFloat(navigator.appVersion); var majorVersion = parseInt(navigator.appVersion, 10); var nameOffset, verOffset, ix;
// In MSIE, the true version is after "MSIE" in userAgent if ((verOffset = nAgt.indexOf("MSIE")) != -1) { browserName = "Microsoft Internet Explorer"; fullVersion = nAgt.substring(verOffset + 5); } else if ( nAgt.indexOf("Trident") != -1 && nAgt.indexOf("rv:11") != -1 ) { browserName = "Microsoft Internet Explorer"; fullVersion = "11"; } // In Opera, the true version is after "Opera" else if ((verOffset = nAgt.indexOf("Opera")) != -1) { browserName = "Opera"; fullVersion = nAgt.substring(verOffset + 6); } // In Chrome, the true version is after "Chrome" else if ((verOffset = nAgt.indexOf("Chrome")) != -1) { browserName = "Chrome"; fullVersion = nAgt.substring(verOffset + 7); } // In Safari, the true version is after "Safari" else if ((verOffset = nAgt.indexOf("Safari")) != -1) { browserName = "Safari"; fullVersion = nAgt.substring(verOffset + 7); } // In Firefox, the true version is after "Firefox" else if ((verOffset = nAgt.indexOf("Firefox")) != -1) { browserName = "Firefox"; fullVersion = nAgt.substring(verOffset + 8); } // In most other browsers, "name/version" is at the end of userAgent else if ( (nameOffset = nAgt.lastIndexOf(" ") + 1) < (verOffset = nAgt.lastIndexOf("/")) ) { browserName = nAgt.substring(nameOffset, verOffset); fullVersion = nAgt.substring(verOffset + 1); if (browserName.toLowerCase() == browserName.toUpperCase()) { browserName = navigator.appName; } }
// trim the fullVersion string at semicolon/space if present if ((ix = fullVersion.indexOf(";")) != -1) fullVersion = fullVersion.substring(0, ix); if ((ix = fullVersion.indexOf(" ")) != -1) fullVersion = fullVersion.substring(0, ix); majorVersion = parseInt("" + fullVersion, 10);
if (isNaN(majorVersion)) { fullVersion = "" + parseFloat(navigator.appVersion); majorVersion = parseInt(navigator.appVersion, 10); } document.getElementById("browser").innerHTML = "OS: " + jscd.os + " " + jscd.osVersion + " x" + jscd.osArch + jscd.mobile + "; Browser: " + browserName + " " + fullVersion; if (browserName == "Microsoft Internet Explorer" && majorVersion < 8) { document.getElementById("browserPass").innerHTML = failString; } else document.getElementById("browserPass").innerHTML = passString; }
function get_bits_system_architecture() { var _to_check = []; if (window.navigator.cpuClass) _to_check.push((window.navigator.cpuClass + "").toLowerCase()); if (window.navigator.platform) _to_check.push((window.navigator.platform + "").toLowerCase()); if (navigator.userAgent) _to_check.push((navigator.userAgent + "").toLowerCase());
var _64bits_signatures = [ "x86_64", "x86-64", "Win64", "x64;", "amd64", "AMD64", "WOW64", "x64_64", "ia64", "sparc64", "ppc64", "IRIX64", ]; var _bits = 32, _i, _c; outer_loop: for (var _c = 0; _c < _to_check.length; _c++) { for (_i = 0; _i < _64bits_signatures.length; _i++) { if ( _to_check[_c].indexOf(_64bits_signatures[_i].toLowerCase()) != -1 ) { _bits = 64; break outer_loop; } } } return _bits; }
function is_32bits_architecture() { return get_bits_system_architecture() == 32 ? 1 : 0; } function is_64bits_architecture() { return get_bits_system_architecture() == 64 ? 1 : 0; }
function checkPKCS11Info() { document.getElementById("versionPass").innerHTML = failString; document.getElementById("libraryPass").innerHTML = failString; document.getElementById("slotPass").innerHTML = failString; document.getElementById("subVersionPass").innerHTML = failString; document.getElementById("hipkiLocalSignServerVersion").innerHTML = "檢測中..."; var xmlreq = new XMLHttpRequest(); xmlreq.onreadystatechange = function () { if (xmlreq.readyState == 4 && xmlreq.status == 200) { var ret = JSON.parse(xmlreq.responseText); document.getElementById("hipkiLocalSignServerVersion").innerHTML = ret.serverVersion; document.getElementById("versionPass").innerHTML = passString; document.getElementById("subVersion").innerHTML = document.getElementById("subVersion").innerHTML + "ListInfo.exe:" + ret.version + "<br/>"; document.getElementById("subVersionPass").innerHTML = passString; document.getElementById("libraryInfo").innerHTML = ret.libraryDescription + ", ver " + ret.libraryVersion; document.getElementById("libraryPass").innerHTML = passString; var slots = ret.slots; var selectSlot = document.getElementById("slotDescription"); selectSlot.innerHTML = ""; for (var index in slots) { var opt = document.createElement("option"); if (slots[index].token instanceof Object) { document.getElementById("slotPass").innerHTML = passString; opt.value = slots[index].slotDescription; opt.innerHTML = slots[index].slotDescription + " 卡號:[" + slots[index].token.serialNumber + "]"; } else { opt.innerHTML = slots[index].slotDescription + " 未插入卡片"; } selectSlot.appendChild(opt); } } else { document.getElementById("hipkiLocalSignServerVersion").innerHTML = "未安裝元件"; document.getElementById("versionPass").innerHTML = failString; } }; xmlreq.open("POST", "/pkcs11info", true); xmlreq.send();
var xmlreq2 = new XMLHttpRequest(); xmlreq2.onreadystatechange = function () { if (xmlreq2.readyState == 4 && xmlreq2.status == 200) { var ret = JSON.parse(xmlreq2.responseText); document.getElementById("subVersion").innerHTML = document.getElementById("subVersion").innerHTML + " HiPKISign.exe:" + ret.version + "<br/>"; document.getElementById("subVersionPass").innerHTML = passString; } }; xmlreq2.open("POST", "/sign", true); xmlreq2.send('tbsPackage={"tbs":"123","pin":1234}');
var xmlreq3 = new XMLHttpRequest(); xmlreq3.onreadystatechange = function () { if (xmlreq3.readyState == 4 && xmlreq3.status == 200) { var ret = JSON.parse(xmlreq3.responseText); document.getElementById("subVersion").innerHTML = document.getElementById("subVersion").innerHTML + " HiPKIDecrypt.exe:" + ret.version + "<br/>"; document.getElementById("subVersionPass").innerHTML = passString; } }; xmlreq3.open("POST", "/decrypt", true); xmlreq3.send('tbsPackage={"cipher":"123","pin":1234}'); } function getCertInfo() { document.getElementById("signCert").innerHTML = "憑證資料讀取中...."; document.getElementById("encryptCert").innerHTML = "憑證資料讀取中....";
var xmlreq = new XMLHttpRequest(); xmlreq.onreadystatechange = function () { if (xmlreq.readyState == 4 && xmlreq.status == 200) { var ret = JSON.parse(xmlreq.responseText); var slots = ret.slots; var selectSlot = document.getElementById("slotDescription"); for (var index in slots) { if (slots[index].slotDescription != selectSlot.value) continue; var certs = slots[index].token.certs; for (var indexCert in certs) { var notAfter = new Date(certs[indexCert].notAfterT * 1000); var notBefore = new Date(certs[indexCert].notBeforeT * 1000); var validity = "自" + notBefore.getFullYear() + "年" + (notBefore.getMonth() + 1) + "月" + notBefore.getDate() + "日 至 " + notAfter.getFullYear() + "年" + (notAfter.getMonth() + 1) + "月" + notAfter.getDate() + "日"; var certInfo = "憑證主體:" + certs[indexCert].subjectDN + "<br/>憑證序號:" + certs[indexCert].sn + "<br/>憑證效期:" + validity + "<br/>金鑰用途:" + certs[indexCert].usage; if (certs[indexCert].label === "cert1") { document.getElementById("signCertPass").innerHTML = passString; document.getElementById("signCert").innerHTML = certInfo; } else if (certs[indexCert].label === "cert2") { document.getElementById("encryptCertPass").innerHTML = passString; document.getElementById("encryptCert").innerHTML = certInfo; } } } } else { } }; xmlreq.open("GET", "/pkcs11info?withcert=true", true); xmlreq.send(); }
function startTest() { if (!document.getElementById("slotDescription").value) { alert("請將卡片插入讀卡機,並選擇插入卡片的讀卡機"); } var xmlreq = new XMLHttpRequest(); var tbsData = {}; tbsData["tbs"] = "TBS"; tbsData["hashAlgorithm"] = "SHA256"; tbsData["pin"] = encodeURIComponent( document.getElementsByName("pin")[0].value ); if (tbsData["pin"].length < 6) { alert("PIN碼至少需6碼"); return; } tbsData["func"] = "MakeSignature"; tbsData["signatureType"] = "PKCS7"; tbsData["slotDescription"] = document.getElementById("slotDescription").value; var json = JSON.stringify(tbsData);
xmlreq.open("POST", "/sign", false); xmlreq.send("tbsPackage=" + json); if (xmlreq.readyState == 4 && xmlreq.status == 200) { var ret = JSON.parse(xmlreq.responseText); if (ret.ret_code != 0) { var msg = "簽章檢測失敗, 代碼=" + ret.ret_code.toString(16) + ", 原因:" + ret.message; if (ret.last_error) msg = msg + ", 次代碼=" + ret.last_error + ", 次原因:" + ret.message2; document.getElementById("pinPass").innerHTML = failString; document.getElementById("signPass").innerHTML = failString; document.getElementById("signResult").innerHTML = msg; alert(msg); return; } document.getElementById("signResult").innerHTML = "簽章驗證功能成功"; document.getElementById("signPass").innerHTML = passString; document.getElementById("pinPass").innerHTML = passString; } else { document.getElementById("signResult").innerHTML = "簽章功能失敗"; document.getElementById("pinPass").innerHTML = failString; document.getElementById("signPass").innerHTML = failString; return; } getCertInfo(); } function onLoadPage() { checkBrowser(); checkPKCS11Info(); } </script> </head>
<body onload="onLoadPage()"> <noscript> <p>您所使用的瀏覽器不支援 JavaScript,或是您已將 JavaScript 功能關閉。</p> <p>要使用本系統,您必須使用 支援 JavaScript 的瀏覽器。</p> </noscript> <table width="80%" class="tab03" border="1" cellpadding="2" cellspacing="1" align="center" > <tbody> <tr style="text-align: center"> <th colspan="3" style="text-align: center">IC卡功能檢測</th> </tr> <tr align="left"> <th bgcolor="#eff5f8" width="40%">檢測項目</th> <td bgcolor="#ffffff" width="5%">結果</td> <td bgcolor="#ffffff">檢測內容</td> </tr> <tr align="left"> <th bgcolor="#eff5f8" width="40%"> 1.作業系統及瀏覽器版本</th> <td bgcolor="#ffffff" width="5%"> <span id="browserPass"></span> </td> <td bgcolor="#ffffff"> <span id="browser"></span> </td> </tr> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 2.已安裝元件版本</th> <td bgcolor="#ffffff" width="5%"> <span id="versionPass"></span> </td> <td bgcolor="#ffffff"> <span id="hipkiLocalSignServerVersion"></span> </td> </tr> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 3.已安裝子元件版本</th> <td bgcolor="#ffffff" width="5%"> <span id="subVersionPass"></span> </td> <td bgcolor="#ffffff"> <span id="subVersion"></span> </td> </tr> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 4.PKCS#11版本資訊</th> <td bgcolor="#ffffff" width="5%"> <span id="libraryPass"></span> </td> <td bgcolor="#ffffff"> <span id="libraryInfo"></span> </td> </tr> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 5.選擇讀卡機及卡片</th> <td bgcolor="#ffffff" width="5%"> <span id="slotPass"></span> </td> <td bgcolor="#ffffff"> <select id="slotDescription"></select> </td> </tr> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 6.輸入PIN碼並開始檢測</th> <td bgcolor="#ffffff" width="5%"> <span id="pinPass"></span> </td> <td bgcolor="#ffffff"> <input type="password" maxlength="12" id="pin" name="pin" /><input type="button" name="startTest" value="開始檢測" onclick="startTest()" /> </td> </tr> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 7.簽章驗證測試</th> <td bgcolor="#ffffff" width="5%"> <span id="signPass"></span> </td> <td bgcolor="#ffffff"> <span id="signResult"></span> </td> </tr> <!--tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 7.加密解密測試</th> <td bgcolor="#ffffff" width="5%"> <span id="encryptPass"></span> </td> <td bgcolor="#ffffff"> <span id="encryptResult"></span> </td> </tr--> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 8.簽章憑證資訊</th> <td bgcolor="#ffffff" width="5%"> <span id="signCertPass"></span> </td> <td bgcolor="#ffffff"> <span id="signCert"></span> </td> </tr> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 9.加密憑證資訊</th> <td bgcolor="#ffffff" width="5%"> <span id="encryptCertPass"></span> </td> <td bgcolor="#ffffff"> <span id="encryptCert"></span> </td> </tr> <tr align="left"> <th class="T11b" bgcolor="#eff5f8"> 重新開始檢測</th> <td bgcolor="#ffffff" width="5%"> <span id="allPass"></span> </td> <td bgcolor="#ffffff"> <input type="button" name="restartTest" value="重新開始檢測" onclick="location.reload()" /> </td> </tr> </tbody> </table> </body></html>