pkijs
Version:
Public Key Infrastructure (PKI) is the basis of how identity and key management is performed on the web today. PKIjs is a pure JavaScript library implementing the formats that are used in PKI applications. It is built on WebCrypto and aspires to make it p
953 lines (842 loc) • 40.6 kB
HTML
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>OCSP response complex example</title>
<script type="text/javascript" src="org/pkijs/common.js"></script>
<script type="text/javascript" src="org/pkijs/asn1.js"></script>
<script type="text/javascript" src="org/pkijs/x509_schema.js"></script>
<script type="text/javascript" src="org/pkijs/x509_simpl.js"></script>
<script type="text/javascript" src="org/pkijs/cms_schema.js"></script>
<script type="text/javascript" src="org/pkijs/cms_simpl.js"></script>
<script type="text/javascript" src="org/pkijs/ocsp_tsp_schema.js"></script>
<script type="text/javascript" src="org/pkijs/ocsp_tsp_simpl.js"></script>
<style type="text/css">
body{background:#EFEFEF;font:normal 14px/16px Helvetica, Arial, sans-serif;}
.wrapper{
width:600px;
margin:50px auto;
padding:50px;
border:solid 2px #CCC;
border-radius:10px;
-webkit-border-radius:10px;
box-shadow:0 0 12px 3px #CDCDCD;
-webkit-box-shadow:0 0 12px 3px #CDCDCD;
background:#FFF;
}
label{
font:bold 16px/20px Helvetica, Arial, sans-serif;
margin:0 0 8px;
}
textarea{
width:500px;
border:solid 1px #999;
border-radius:5px;
-webkit-border-radius:5px;
height:340px;
font:normal 12px/15px monospace;
display:block;
margin:0 0 12px;
box-shadow:0 0 5px 5px #EFEFEF inset;
-webkit-box-shadow:0 0 5px 5px #EFEFEF inset;
padding:20px;
resize: none;
}
a{
display:inline-block;
padding:5px 15px;
background:#ACD0EC;
border:solid 1px #4C6181;
color:#000;
font:normal 14px/16px Helvetica, Arial, sans-serif;
}
a:hover{
background:#DAEBF8;
cursor:pointer;
}
.header-block {
margin-top:30px;
font:bold 16px/20px Helvetica, Arial, sans-serif;
}
.border-block{
border:solid 2px #999;
border-radius:5px;
-webkit-border-radius:5px;
margin:10px 0 0;
padding:20px 30px;
background:#F0F4FF;
}
.border-block h2{
margin:0 0 16px;
font:bold 22px/24px Helvetica, Arial, sans-serif;
}
.border-block p{
margin:0 0 12px;
}
.border-block p .type{
font-weight:bold;
display:inline-block;
width:176px;
}
.border-block .two-col{
overflow:hidden;
margin:0 0 16px;
}
.border-block .two-col .subject{
width:180px;
font-weight:bold;
margin:0 0 12px;
float:left;
}
.border-block .two-col #cms-signed-attributes{
margin:0;
padding:0;
float:left;
list-style:none;
}
.border-block .two-col #cms-signed-attributes li p{
margin:0;
}
.border-block .two-col #cms-signed-attributes li p span{
width:40px;
display:inline-block;
margin:0 0 5px;
}
.border-block .two-col #cms-signed-exten{
overflow:hidden;
padding:0 0 0 17px;
margin:0;
list-style-type:square;
}
table {
border:solid;
border-collapse:collapse;
border-color:black;
}
th {
text-align:center;
background: #ccc;
padding: 5px;
border: 1px solid black;
}
td {
padding: 5px;
border: 1px solid black;
}
</style>
<script>
//*********************************************************************************
var ocspResponseBuffer; // ArrayBuffer with loaded or created OCSP response
var trustedCertificates = new Array(); // Array of root certificates from "CA Bundle"
//*********************************************************************************
// #region Auxiliary functions
//*********************************************************************************
function formatPEM(pem_string)
{
/// <summary>Format string in order to have each line with length equal to 63</summary>
/// <param name="pem_string" type="String">String to format</param>
var string_length = pem_string.length;
var result_string = "";
for(var i = 0, count = 0; i < string_length; i++, count++)
{
if(count > 63)
{
result_string = result_string + "\r\n";
count = 0;
}
result_string = result_string + pem_string[i];
}
return result_string;
}
//*********************************************************************************
function arrayBufferToString(buffer)
{
/// <summary>Create a string from ArrayBuffer</summary>
/// <param name="buffer" type="ArrayBuffer">ArrayBuffer to create a string from</param>
var result_string = "";
var view = new Uint8Array(buffer);
for(var i = 0; i < view.length; i++)
result_string = result_string + String.fromCharCode(view[i]);
return result_string;
}
//*********************************************************************************
function stringToArrayBuffer(str)
{
/// <summary>Create an ArrayBuffer from string</summary>
/// <param name="str" type="String">String to create ArrayBuffer from</param>
var stringLength = str.length;
var resultBuffer = new ArrayBuffer(stringLength);
var resultView = new Uint8Array(resultBuffer);
for(var i = 0; i < stringLength; i++)
resultView[i] = str.charCodeAt(i);
return resultBuffer;
}
//*********************************************************************************
function handleFileBrowse(evt)
{
var temp_reader = new FileReader();
var current_files = evt.target.files;
var current_index = 0;
temp_reader.onload =
function(event)
{
ocspResponseBuffer = event.target.result;
parse_OCSP_resp();
};
temp_reader.readAsArrayBuffer(current_files[0]);
}
//*********************************************************************************
function handleCABundle(evt)
{
var temp_reader = new FileReader();
var current_files = evt.target.files;
temp_reader.onload =
function(event)
{
parseCAbundle(event.target.result);
};
temp_reader.readAsArrayBuffer(current_files[0]);
}
//*********************************************************************************
// #endregion
//*********************************************************************************
// #region Create OCSP response
//*********************************************************************************
function create_OCSP_resp()
{
// #region Initial variables
var sequence = Promise.resolve();
var ocsp_resp_simpl = new org.pkijs.simpl.OCSP_RESPONSE();
var ocsp_basic_resp = new org.pkijs.simpl.OCSP_BASIC_RESPONSE();
var cert_simpl = new org.pkijs.simpl.CERT();
var cms_signed_simpl;
var publicKey;
var privateKey;
var hash_algorithm = "sha-1";
var hash_algorithm_oid = "1.3.14.3.2.26";
var signature_algorithm = "1.2.840.113549.1.1.5";
var hash_option = document.getElementById("hash_alg").value;
switch(hash_option)
{
case "alg_SHA1":
hash_algorithm = "sha-1";
hash_algorithm_oid = "1.3.14.3.2.26";
signature_algorithm = "1.2.840.113549.1.1.5";
break;
case "alg_SHA256":
hash_algorithm = "sha-256";
hash_algorithm_oid = "2.16.840.1.101.3.4.2.1";
signature_algorithm = "1.2.840.113549.1.1.11";
break;
case "alg_SHA384":
hash_algorithm = "sha-384";
hash_algorithm_oid = "2.16.840.1.101.3.4.2.2";
signature_algorithm = "1.2.840.113549.1.1.12";
break;
case "alg_SHA512":
hash_algorithm = "sha-512";
hash_algorithm_oid = "2.16.840.1.101.3.4.2.3";
signature_algorithm = "1.2.840.113549.1.1.13";
break;
default:;
}
// #endregion
// #region Get a "crypto" extension
var crypto = org.pkijs.getCrypto();
if(typeof crypto == "undefined")
{
alert("No WebCrypto extension found");
return;
}
// #endregion
// #region Put a static values
cert_simpl.version = 2;
cert_simpl.serialNumber = new org.pkijs.asn1.INTEGER({ value: 1 });
cert_simpl.issuer.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
type: "2.5.4.6", // Country name
value: new org.pkijs.asn1.PRINTABLESTRING({ value: "RU" })
}));
cert_simpl.issuer.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
type: "2.5.4.3", // Common name
value: new org.pkijs.asn1.BMPSTRING({ value: "Test" })
}));
cert_simpl.subject.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
type: "2.5.4.6", // Country name
value: new org.pkijs.asn1.PRINTABLESTRING({ value: "RU" })
}));
cert_simpl.subject.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
type: "2.5.4.3", // Common name
value: new org.pkijs.asn1.BMPSTRING({ value: "Test" })
}));
cert_simpl.notBefore.value = new Date(2013, 01, 01);
cert_simpl.notAfter.value = new Date(2016, 01, 01);
cert_simpl.extensions = new Array(); // Extensions are not a part of certificate by default, it's an optional array
// #region "BasicConstraints" extension
//var basic_constr = new org.pkijs.simpl.x509.BasicConstraints({
// cA: true,
// pathLenConstraint: 3
//});
//cert_simpl.extensions.push(new org.pkijs.simpl.EXTENSION({
// extnID: "2.5.29.19",
// critical: false,
// extnValue: basic_constr.toSchema().toBER(false),
// parsedValue: basic_constr // Parsed value for well-known extensions
//}));
// #endregion
// #region "KeyUsage" extension
var bit_array = new ArrayBuffer(1);
var bit_view = new Uint8Array(bit_array);
bit_view[0] = bit_view[0] | 0x02; // Key usage "cRLSign" flag
//bit_view[0] = bit_view[0] | 0x04; // Key usage "keyCertSign" flag
var key_usage = new org.pkijs.asn1.BITSTRING({ value_hex: bit_array });
cert_simpl.extensions.push(new org.pkijs.simpl.EXTENSION({
extnID: "2.5.29.15",
critical: false,
extnValue: key_usage.toBER(false),
parsedValue: key_usage // Parsed value for well-known extensions
}));
// #endregion
cert_simpl.signatureAlgorithm.algorithm_id = signature_algorithm;
cert_simpl.signature.algorithm_id = cert_simpl.signatureAlgorithm.algorithm_id; // Must be the same value
// #endregion
// #region Create a new key pair
sequence = sequence.then(
function()
{
return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: hash_algorithm } }, true, ["sign", "verify"]);
}
);
// #endregion
// #region Store new key in an interim variables
sequence = sequence.then(
function(keyPair)
{
publicKey = keyPair.publicKey;
privateKey = keyPair.privateKey;
},
function(error)
{
alert("Error during key generation: " + error);
}
);
// #endregion
// #region Exporting public key into "subjectPublicKeyInfo" value of certificate
sequence = sequence.then(
function()
{
return cert_simpl.subjectPublicKeyInfo.importKey(publicKey);
}
);
// #endregion
// #region Signing final certificate
sequence = sequence.then(
function()
{
return cert_simpl.sign(privateKey);
},
function(error)
{
alert("Error during exporting public key: " + error);
}
);
// #endregion
// #region Encode and store certificate
sequence = sequence.then(
function()
{
var cert_simpl_encoded = cert_simpl.toSchema(true).toBER(false);
var cert_simpl_string = String.fromCharCode.apply(null, new Uint8Array(cert_simpl_encoded));
var result_string = "-----BEGIN CERTIFICATE-----\r\n";
result_string = result_string + formatPEM(window.btoa(cert_simpl_string));
result_string = result_string + "\r\n-----END CERTIFICATE-----\r\n";
document.getElementById("new_signed_data").innerHTML = result_string;
alert("Certificate created successfully!");
},
function(error)
{
alert("Error during signing: " + error);
}
);
// #endregion
// #region Exporting private key
sequence = sequence.then(
function()
{
return crypto.exportKey("pkcs8", privateKey);
}
);
// #endregion
// #region Store exported key on Web page
sequence = sequence.then(
function(result)
{
var private_key_string = String.fromCharCode.apply(null, new Uint8Array(result));
var result_string = document.getElementById("new_signed_data").innerHTML;
result_string = result_string + "\r\n-----BEGIN PRIVATE KEY-----\r\n";
result_string = result_string + formatPEM(window.btoa(private_key_string));
result_string = result_string + "\r\n-----END PRIVATE KEY-----\r\n";
document.getElementById("new_signed_data").innerHTML = result_string;
alert("Private key exported successfully!");
},
function(error)
{
alert("Error during exporting of private key: " + error);
}
);
// #endregion
// #region Create specific TST info structure to sign
sequence = sequence.then(
function()
{
ocsp_resp_simpl.responseStatus.value_block.value_dec = 0; // success
ocsp_resp_simpl.responseBytes = new org.pkijs.simpl.ocsp.ResponseBytes();
ocsp_resp_simpl.responseBytes.responseType = "1.3.6.1.5.5.7.48.1.1"
var responderIDBuffer = new ArrayBuffer(1);
var responderIDView = new Uint8Array(responderIDBuffer);
responderIDView[0] = 0x01;
ocsp_basic_resp.tbsResponseData.responderID = cert_simpl.issuer;
ocsp_basic_resp.tbsResponseData.producedAt = new Date();
var response = new org.pkijs.simpl.ocsp.SingleResponse();
response.certID.hashAlgorithm.algorithm_id = "1.3.14.3.2.26"; // SHA-1
response.certID.issuerNameHash.value_block.value_hex = responderIDBuffer; // Fiction hash
response.certID.issuerKeyHash.value_block.value_hex = responderIDBuffer; // Fiction hash
response.certID.serialNumber.value_block.value_dec = 1; // Fiction serial number
response.certStatus = new org.pkijs.asn1.ASN1_PRIMITIVE({
id_block: {
tag_class: 3, // CONTEXT-SPECIFIC
tag_number: 0 // [0]
},
len_block_length: 1 // The length contains one byte 0x00
}); // status - success
response.thisUpdate = new Date();
ocsp_basic_resp.tbsResponseData.responses.push(response);
ocsp_basic_resp.signatureAlgorithm.algorithm_id = "1.2.840.113549.1.1.5"; // RSA + SHA-1
ocsp_basic_resp.certs = [cert_simpl];
return ocsp_basic_resp.sign(privateKey);
}
);
// #endregion
sequence = sequence.then(
function(result)
{
var encodedOCSPBasicResp = ocsp_basic_resp.toSchema().toBER(false);
var asn1_basic = org.pkijs.fromBER(encodedOCSPBasicResp);
var decodedResponse = new org.pkijs.simpl.OCSP_BASIC_RESPONSE({ schema: asn1_basic.result });
var schema = ocsp_basic_resp.tbsResponseData.toSchema();
var encodedBMP = ocsp_basic_resp.tbsResponseData.toSchema().toBER(false);
var asn1_mp = org.pkijs.fromBER(encodedBMP);
return decodedResponse.verify();
}
);
// #region Finally create completed OCSP response structure
sequence.then(
function(result)
{
var encodedOCSPBasicResp = ocsp_basic_resp.toSchema().toBER(false);
ocsp_resp_simpl.responseBytes.response = new org.pkijs.asn1.OCTETSTRING({ value_hex: encodedOCSPBasicResp });
ocspResponseBuffer = ocsp_resp_simpl.toSchema().toBER(false);
// #region Convert ArrayBuffer to String
var signed_data_string = "";
var view = new Uint8Array(ocspResponseBuffer);
for(var i = 0; i < view.length; i++)
signed_data_string = signed_data_string + String.fromCharCode(view[i]);
// #endregion
var result_string = document.getElementById("new_signed_data").innerHTML;
result_string = result_string + "\r\n-----BEGIN OCSP RESPONSE-----\r\n";
result_string = result_string + formatPEM(window.btoa(signed_data_string));
result_string = result_string + "\r\n-----END OCSP RESPONSE-----\r\n\r\n";
document.getElementById("new_signed_data").innerHTML = result_string;
parse_OCSP_resp();
alert("OCSP response has created successfully!");
}
);
// #endregion
}
//*********************************************************************************
// #endregion
//*********************************************************************************
// #region Parse existing OCSP response
//*********************************************************************************
function parse_OCSP_resp()
{
// #region Initial activities
document.getElementById("ocsp-resp-extensions").style.display = "none";
document.getElementById("ocsp-resp-rspid-rdn").style.display = "none";
document.getElementById("ocsp-resp-rspid-simpl").style.display = "none";
var respIDTable = document.getElementById("ocsp-resp-respid-rdn");
while(respIDTable.rows.length > 1)
{
respIDTable.deleteRow(respIDTable.rows.length - 1);
}
var extensionTable = document.getElementById("ocsp-resp-extensions-table");
while(extensionTable.rows.length > 1)
{
extensionTable.deleteRow(extensionTable.rows.length - 1);
}
var responsesTable = document.getElementById("ocsp-resp-attr-table");
while(extensionTable.rows.length > 1)
{
extensionTable.deleteRow(extensionTable.rows.length - 1);
}
// #endregion
// #region Decode existing OCSP response
var asn1 = org.pkijs.fromBER(ocspResponseBuffer);
var ocsp_resp_simpl = new org.pkijs.simpl.OCSP_RESPONSE({ schema: asn1.result });
var asn1_basic = org.pkijs.fromBER(ocsp_resp_simpl.responseBytes.response.value_block.value_hex);
var ocsp_basic_resp = new org.pkijs.simpl.OCSP_BASIC_RESPONSE({ schema: asn1_basic.result });
// #endregion
// #region Put information about overall response status
var status = "";
switch(ocsp_resp_simpl.responseStatus.value_block.value_dec)
{
case 0:
status = "successful";
break;
case 1:
status = "malformedRequest";
break;
case 2:
status = "internalError";
break;
case 3:
status = "tryLater";
break;
case 4:
status = "<not used>";
break;
case 5:
status = "sigRequired";
break;
case 6:
status = "unauthorized";
break;
default:
alert("Wrong OCSP response status");
return;
}
document.getElementById("resp-status").innerHTML = status;
// #endregion
// #region Put information about signature algorithm
var algomap = {
"1.2.840.113549.2.1": "MD2",
"1.2.840.113549.1.1.2": "MD2 with RSA",
"1.2.840.113549.2.5": "MD5",
"1.2.840.113549.1.1.4": "MD5 with RSA",
"1.3.14.3.2.26": "SHA1",
"1.2.840.10040.4.3": "SHA1 with DSA",
"1.2.840.10045.4.1": "SHA1 with ECDSA",
"1.2.840.113549.1.1.5": "SHA1 with RSA",
"2.16.840.1.101.3.4.2.4": "SHA224",
"1.2.840.113549.1.1.14": "SHA224 with RSA",
"2.16.840.1.101.3.4.2.1": "SHA256",
"1.2.840.113549.1.1.11": "SHA256 with RSA",
"2.16.840.1.101.3.4.2.2": "SHA384",
"1.2.840.113549.1.1.12": "SHA384 with RSA",
"2.16.840.1.101.3.4.2.3": "SHA512",
"1.2.840.113549.1.1.13": "SHA512 with RSA"
};
var signatureAlgorithm = algomap[ocsp_basic_resp.signatureAlgorithm.algorithm_id];
if(typeof signatureAlgorithm === "undefined")
signatureAlgorithm = ocsp_basic_resp.signatureAlgorithm.algorithm_id;
else
signatureAlgorithm = signatureAlgorithm + " (" + ocsp_basic_resp.signatureAlgorithm.algorithm_id + ")";
document.getElementById("sig-algo").innerHTML = signatureAlgorithm;
// #endregion
// #region Put information about "Responder ID"
if(ocsp_basic_resp.tbsResponseData.responderID instanceof org.pkijs.simpl.RDN)
{
var typemap = {
"2.5.4.6": "C",
"2.5.4.10": "OU",
"2.5.4.11": "O",
"2.5.4.3": "CN",
"2.5.4.7": "L",
"2.5.4.8": "S",
"2.5.4.12": "T",
"2.5.4.42": "GN",
"2.5.4.43": "I",
"2.5.4.4": "SN",
"1.2.840.113549.1.9.1": "E-mail"
};
for(var i = 0; i < ocsp_basic_resp.tbsResponseData.responderID.types_and_values.length; i++)
{
var typeval = typemap[ocsp_basic_resp.tbsResponseData.responderID.types_and_values[i].type];
if(typeof typeval === "undefined")
typeval = ocsp_basic_resp.tbsResponseData.responderID.types_and_values[i].type;
var subjval = ocsp_basic_resp.tbsResponseData.responderID.types_and_values[i].value.value_block.value;
var row = respIDTable.insertRow(respIDTable.rows.length);
var cell0 = row.insertCell(0);
cell0.innerHTML = typeval;
var cell1 = row.insertCell(1);
cell1.innerHTML = subjval;
}
document.getElementById("ocsp-resp-rspid-rdn").style.display = "block";
}
else
{
if(ocsp_basic_resp.tbsResponseData.responderID instanceof org.pkijs.asn1.OCTETSTRING)
{
document.getElementById("ocsp-resp-respid-simpl").innerHTML = org.pkijs.bufferToHexCodes(ocsp_basic_resp.tbsResponseData.responderID.value_block.value_hex, 0, ocsp_basic_resp.tbsResponseData.responderID.value_block.value_hex.byteLength);
document.getElementById("ocsp-resp-rspid-simpl").style.display = "block";
}
else
{
alert("Wrong OCSP response responderID");
return;
}
}
// #endregion
// #region Put information about a time when the response was produced
document.getElementById("prod-at").innerHTML = ocsp_basic_resp.tbsResponseData.producedAt.toString();
// #endregion
// #region Put information about extensions of the OCSP response
if("responseExtensions" in ocsp_basic_resp)
{
var extenmap = {
"1.3.6.1.5.5.7.48.1.2": "Nonce",
"1.3.6.1.5.5.7.48.1.3": "CRL References",
"1.3.6.1.5.5.7.48.1.4": "Acceptable Response Types",
"1.3.6.1.5.5.7.48.1.6": "Archive Cutoff",
"1.3.6.1.5.5.7.48.1.7": "Service Locator",
"1.3.6.1.5.5.7.48.1.8": "Preferred Signature Algorithms",
"1.3.6.1.5.5.7.48.1.9": "Extended Revoked Definition",
"2.5.29.21": "CRL Reason",
"2.5.29.24": "Invalidity Date",
"2.5.29.29": "Certificate Issuer",
"1.3.6.1.4.1.311.21.4": "Next Update"
};
for(var i = 0; i < ocsp_basic_resp.responseExtensions.length; i++)
{
var typeval = typemap[ocsp_basic_resp.responseExtensions[i].extnID];
if(typeof typeval === "undefined")
typeval = ocsp_basic_resp.responseExtensions[i].extnID;
var row = extensionTable.insertRow(extensionTable.rows.length);
var cell0 = row.insertCell(0);
cell0.innerHTML = typeval;
}
document.getElementById("ocsp-resp-extensions").style.display = "block";
}
// #endregion
// #region Put information about OCSP responses
for(var i = 0; i < ocsp_basic_resp.tbsResponseData.responses.length; i++)
{
var typeval = org.pkijs.bufferToHexCodes(ocsp_basic_resp.tbsResponseData.responses[i].certID.serialNumber.value_block.value_hex);
var subjval = "";
switch(ocsp_basic_resp.tbsResponseData.responses[i].certStatus.id_block.tag_number)
{
case 0:
subjval = "good";
break;
case 1:
subjval = "revoked";
break;
case 2:
default:
subjval = "unknown";
}
var row = responsesTable.insertRow(responsesTable.rows.length);
var cell0 = row.insertCell(0);
cell0.innerHTML = typeval;
var cell1 = row.insertCell(1);
cell1.innerHTML = subjval;
}
// #endregion
document.getElementById("ocsp-resp-data-block").style.display = "block";
}
//*********************************************************************************
// #endregion
//*********************************************************************************
// #region Verify existing OCSP response
//*********************************************************************************
function verify_OCSP_resp()
{
// #region Decode existing OCSP response
var asn1 = org.pkijs.fromBER(ocspResponseBuffer);
var ocsp_resp_simpl = new org.pkijs.simpl.OCSP_RESPONSE({ schema: asn1.result });
var asn1_basic = org.pkijs.fromBER(ocsp_resp_simpl.responseBytes.response.value_block.value_hex);
var ocsp_basic_resp = new org.pkijs.simpl.OCSP_BASIC_RESPONSE({ schema: asn1_basic.result });
// #endregion
// #region Verify OCSP response
ocsp_basic_resp.verify({ trusted_certs: trustedCertificates }).
then(
function(result)
{
alert("Verification result: " + result);
},
function(error)
{
alert("Error during verification: " + error);
}
);
// #endregion
}
//*********************************************************************************
// #endregion
//*********************************************************************************
// #region Parse "CA Bundle" file
//*********************************************************************************
function parseCAbundle(buffer)
{
// #region Initial variables
var base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var startChars = "-----BEGIN CERTIFICATE-----";
var endChars = "-----END CERTIFICATE-----";
var endLineChars = "\r\n";
var view = new Uint8Array(buffer);
var waitForStart = false;
var middleStage = true;
var waitForEnd = false;
var waitForEndLine = false;
var started = false;
var certBodyEncoded = "";
// #endregion
for(var i = 0; i < view.length; i++)
{
if(started === true)
{
if(base64Chars.indexOf(String.fromCharCode(view[i])) !== (-1))
certBodyEncoded = certBodyEncoded + String.fromCharCode(view[i]);
else
{
if(String.fromCharCode(view[i]) === '-')
{
// #region Decoded trustedCertificates
var asn1 = org.pkijs.fromBER(stringToArrayBuffer(window.atob(certBodyEncoded)));
try
{
trustedCertificates.push(new org.pkijs.simpl.CERT({ schema: asn1.result }));
}
catch(ex)
{
alert("Wrong certificate format");
return;
}
// #endregion
// #region Set all "flag variables"
certBodyEncoded = "";
started = false;
waitForEnd = true;
// #endregion
}
}
}
else
{
if(waitForEndLine === true)
{
if(endLineChars.indexOf(String.fromCharCode(view[i])) === (-1))
{
waitForEndLine = false;
if(waitForEnd === true)
{
waitForEnd = false;
middleStage = true;
}
else
{
if(waitForStart === true)
{
waitForStart = false;
started = true;
certBodyEncoded = certBodyEncoded + String.fromCharCode(view[i]);
}
else
middleStage = true;
}
}
}
else
{
if(middleStage === true)
{
if(String.fromCharCode(view[i]) === "-")
{
if((i === 0) ||
((String.fromCharCode(view[i - 1]) === "\r") ||
(String.fromCharCode(view[i - 1]) === "\n")))
{
middleStage = false;
waitForStart = true;
}
}
}
else
{
if(waitForStart === true)
{
if(startChars.indexOf(String.fromCharCode(view[i])) === (-1))
waitForEndLine = true;
}
else
{
if(waitForEnd === true)
{
if(endChars.indexOf(String.fromCharCode(view[i])) === (-1))
waitForEndLine = true;
}
}
}
}
}
}
}
//*********************************************************************************
// #endregion
//*********************************************************************************
</script>
</head>
<body>
<div class="wrapper">
<p class="header-block">Create new OCSP response</p>
<div id="add-tsp-resp-block" class="border-block">
<p>
<label for="hash_alg" style="font-weight:bold">Hashing algorithm:</label>
<select id="hash_alg">
<option value="alg_SHA1">SHA-1</option>
<option value="alg_SHA256">SHA-256</option>
<option value="alg_SHA384">SHA-384</option>
<option value="alg_SHA512">SHA-512</option>
</select>
</p>
<label for="new_signed_data" style="font-weight:bold;float:left;">OCSP resp data + BASE-64 encoded new certificate + PKCS#8 private key:</label>
<textarea id="new_signed_data">< New OCSP response data + new encoded certificate + PKCS#8 exported private key will be stored here ></textarea>
<a onclick="create_OCSP_resp();">Create</a>
</div>
<p class="header-block">Parse loaded/created TSP response</p>
<div id="ocsp-resp-data-block" class="border-block">
<p>
<label for="temp_file">Select OCSP response file (DER):</label>
<input type="file" id="temp_file" title="OCSP response" />
</p>
<p><span class="type">Response status:</span> <span id="resp-status"></span></p>
<p><span class="type">Signature Algorithm:</span> <span id="sig-algo"></span></p>
<div id="ocsp-resp-rspid-rdn" class="two-col" style="display:none;">
<p class="subject">Responder ID:</p>
<table id="ocsp-resp-respid-rdn"><tr><th>RDN OID</th><th>RDN value</th></tr></table>
</div>
<p id="ocsp-resp-rspid-simpl" style="display:none;"><span class="type">Responder ID:</span> <span id="ocsp-resp-respid-simpl"></span></p>
<p><span class="type">Produced at:</span> <span id="prod-at"></span></p>
<div id="ocsp-resp-attributes" class="two-col">
<p class="subject">Responses:</p>
<table id="ocsp-resp-attr-table"><tr><th>Cert num.</th><th>Status</th></tr></table>
</div>
<div id="ocsp-resp-extensions" class="two-col" style="display:none;">
<p class="subject">Extensions:</p>
<table id="ocsp-resp-extensions-table"><tr><th>Extension OID</th></tr></table>
</div>
</div>
<p class="header-block">Verify loaded/created OCSP response</p>
<div class="border-block">
<p>
<label for="ca_bundle">Load "CA bundle":</label>
<input type="file" id="ca_bundle" title="Input file" />
</p>
<a onclick="verify_OCSP_resp();">Verify</a>
</div>
</div>
<script>
document.getElementById('temp_file').addEventListener('change', handleFileBrowse, false);
document.getElementById('ca_bundle').addEventListener('change', handleCABundle, false);
</script>
</body>
</html>