One of the things that we wanted you to be able to use the PKI.js libraries for is the X.509 Certificates, including those with new extensions (like testing for OCSP MUST Staple or for testing other certificate processing libraries like was done in the Frankencert paper.
Here is an example of what that might look like:
function create_cert()
{
// #region Initial variables
var sequence = Promise.resolve();
var cert_simpl = new org.pkijs.simpl.CERT();
var publicKey;
var privateKey;
// #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.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.222.333",
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.222.444",
value: new org.pkijs.asn1.PRINTABLESTRING({ value: "Test" })
}));
cert_simpl.subject.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({
type: "2.222.333",
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.222.444",
value: new org.pkijs.asn1.PRINTABLESTRING({ value: "Test" })
}));
cert_simpl.notBefore.value = new Date();
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 = "1.2.840.113549.1.1.5"; // RSA + SHA-1
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: "sha-1" } }, true, ["encrypt", "decrypt", "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"
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
sequence = sequence.then(
function()
{
alert("Good result");
},
function(error)
{
alert("Error during signing: " + error);
}
);
sequence.then(
function()
{
return cert_simpl.verify();
}
).then(
function(result)
{
alert("Verification passed: " + result);
},
function(error)
{
alert("Verification failed: " + eror);
}
);
}
As you can see the library is designed in such a way you are not limited to the creation of some static pre-conceived layouts of these structures, you can fairly easily construct any type of certificate (or any of the other supported message types).
At a later date (if it makes sense to do so) we may also decide to add a simple layer ontop of this that abstracts out the need to understand encoding concepts as well.
This layered approach ensures the library can be used to create real-applications without the need to hack up the underlying APIs enabling developers to avoid the need to understand low-level ASN.1 formats in detail.