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

首頁 > 系列文 > 自然人憑證開發筆記


/selfTest.htm#

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


Request#

Terminal window
GET http://127.0.0.1:61161/selfTest.htm

Response#

<!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>