crlgenerator.js
Summary
Simple CRL generator class
Class Summary
|
CRLGenerator |
Class implementing a CRL certificate generator
|
if (typeof(__ScriptingServer) == "undefined") {
load("pkixcommon.js");
}
function CRLGenerator(crypto) {
this.crypto = crypto;
this.reset();
}
CRLGenerator.unspecified = 0;
CRLGenerator.keyCompromise = 1;
CRLGenerator.cACompromise = 2;
CRLGenerator.affiliationChanged = 3;
CRLGenerator.superseded = 4;
CRLGenerator.cessationOfOperation = 5;
CRLGenerator.certificateHold = 6;
CRLGenerator.removeFromCRL = 8;
CRLGenerator.privilegeWithdrawn = 9;
CRLGenerator.aACompromise = 10;
CRLGenerator.prototype.reset = function() {
this.extensions = [];
this.revokedCertificates = [];
this.nextUpdate = null;
}
CRLGenerator.prototype.setIssuer = function(issuer) {
this.issuer = issuer;
}
CRLGenerator.prototype.setThisUpdate = function(datetime) {
this.thisUpdate = datetime;
}
CRLGenerator.prototype.setNextUpdate = function(datetime) {
this.nextUpdate = datetime;
}
CRLGenerator.prototype.setSignatureAlgorithm = function(alg) {
this.signatureAlgorithm = alg;
}
CRLGenerator.prototype.addExtension = function(extnID, critical, extnValue) {
var t = new ASN1("extension", ASN1.SEQUENCE,
new ASN1("extnID", ASN1.OBJECT_IDENTIFIER, new ByteString(extnID, OID))
);
if (critical) {
t.add(new ASN1("critical", ASN1.BOOLEAN, new ByteString("FF", HEX)));
}
t.add(new ASN1("extnValue", ASN1.OCTET_STRING, extnValue));
this.extensions.push(t);
}
CRLGenerator.prototype.addAuthorityKeyIdentifierExtension = function(publicKey) {
if (publicKey.getComponent(Key.MODULUS)) {
var spi = PKIXCommon.createRSASubjectPublicKeyInfo(publicKey);
} else {
var spi = PKIXCommon.createECSubjectPublicKeyInfo(publicKey, this.encodeECDomainParameter);
}
var keyvalue = spi.get(1).value.bytes(1);
var hash = this.crypto.digest(Crypto.SHA_1, keyvalue);
var t = new ASN1(ASN1.SEQUENCE,
new ASN1(0x80, hash)
);
this.addExtension("id-ce-authorityKeyIdentifier", false, t.getBytes());
}
CRLGenerator.prototype.addCRLNumberExtension = function(crlnumber) {
var t = new ASN1(ASN1.INTEGER,
PKIXCommon.convertUnsignedInteger(ByteString.valueOf(crlnumber))
);
this.addExtension("id-ce-cRLNumber", false, t.getBytes());
}
CRLGenerator.prototype.addRevokedCertificate = function(revokedCertificate) {
this.revokedCertificates.push(revokedCertificate);
}
CRLGenerator.prototype.revokeCertificate = function(serial, timestamp, reason, ext) {
if (typeof(timestamp) == "undefined") {
timestamp = new Date();
}
var t = new ASN1("revokedCertificate", ASN1.SEQUENCE,
new ASN1("userCertificate", ASN1.INTEGER, PKIXCommon.convertUnsignedInteger(serial)),
new ASN1("revocationTime", ASN1.UTCTime, new ByteString(PKIXCommon.dtoUTC(timestamp), ASCII))
);
if (typeof(ext) == "undefined") {
ext = new ASN1("crlExtensions", ASN1.SEQUENCE);
}
if ((typeof(reason) != "undefined") && (reason != -1)) {
ext.add(new ASN1("reason", ASN1.SEQUENCE,
new ASN1("extnID", ASN1.OBJECT_IDENTIFIER, new ByteString("id-ce-cRLReasons", OID)),
new ASN1("extnValue", ASN1.OCTET_STRING,
(new ASN1("cRLReason", ASN1.ENUMERATED, ByteString.valueOf(reason))).getBytes())
)
);
t.add(ext);
}
this.revokedCertificates.push(t);
}
CRLGenerator.prototype.loadCRLEntries = function(filename) {
var crlnumber = 0;
try {
var crlbin = PKIXCommon.readFileFromDisk(filename);
var crl = new ASN1(crlbin);
print(crl);
var tbs = crl.get(0);
var i = 0;
if ((i < tbs.length) && (tbs.get(i).tag == ASN1.INTEGER)) {
i++;
}
i += 3;
if ((i < tbs.length) && (tbs.get(i).tag == ASN1.UTCTime)) {
i++;
}
if ((i < tbs.length) && (tbs.get(i).tag == ASN1.SEQUENCE)) {
for (var j = 0; j < tbs.get(i).elements; j++) {
this.revokedCertificates.push(tbs.get(i).get(j));
}
i++;
}
if ((i < tbs.length) && (tbs.get(i).tag == 0xA0)) {
var l = tbs.get(i).get(0);
var oid = new ByteString("id-ce-cRLNumber", OID);
for (var j = 0; j < l.elements; j++) {
var ext = l.get(j);
if (ext.get(0).value.equals(oid)) {
var extval = new ASN1(ext.get(1).value);
crlnumber = extval.value.toUnsigned();
}
}
}
}
catch(e) {
GPSystem.trace(e);
return -1;
}
return crlnumber;
}
CRLGenerator.prototype.getIssuer = function() {
if (this.issuer instanceof ASN1) {
return this.issuer;
} else {
return PKIXCommon.encodeName(this.issuer);
}
}
CRLGenerator.prototype.getThisUpdate = function() {
var t = new ASN1("thisUpdate", ASN1.UTCTime, new ByteString(PKIXCommon.dtoUTC(this.thisUpdate), ASCII));
return t;
}
CRLGenerator.prototype.getNextUpdate = function() {
var t = new ASN1("nextUpdate", ASN1.UTCTime, new ByteString(PKIXCommon.dtoUTC(this.nextUpdate), ASCII));
return t;
}
CRLGenerator.prototype.getSignatureAlgorithm = function() {
var t = new ASN1("signatureAlgorithm", ASN1.SEQUENCE);
if (this.signatureAlgorithm == Crypto.RSA) {
t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("1.2.840.113549.1.1.5", OID)));
t.add(new ASN1("parameters", ASN1.NULL, new ByteString("", HEX)));
} else if (this.signatureAlgorithm == Crypto.RSA_SHA256) {
t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("1.2.840.113549.1.1.11", OID)));
t.add(new ASN1("parameters", ASN1.NULL, new ByteString("", HEX)));
} else if (this.signatureAlgorithm == Crypto.ECDSA_SHA256) {
t.add(new ASN1("algorithm", ASN1.OBJECT_IDENTIFIER, new ByteString("ecdsa-with-SHA256", OID)));
t.add(new ASN1("parameters", ASN1.NULL, new ByteString("", HEX)));
} else {
throw new GPError("CRLGenerator", GPError.INVALID_MECH, this.signatureAlgorithm, "Invalid algorithm");
}
return t;
}
CRLGenerator.prototype.getRevokedCertificates = function() {
var t = new ASN1("revokedCertificates", ASN1.SEQUENCE);
for (var i = 0; i < this.revokedCertificates.length; i++) {
t.add(this.revokedCertificates[i]);
}
return t;
}
CRLGenerator.prototype.getExtensions = function() {
var t = new ASN1("extensions", 0xA0);
var s = new ASN1("extensions", ASN1.SEQUENCE);
t.add(s);
for (var i = 0; i < this.extensions.length; i++) {
s.add(this.extensions[i]);
}
return t;
}
CRLGenerator.prototype.getTbsCertificateList = function() {
var t = new ASN1("tbsCertList", ASN1.SEQUENCE);
t.add(new ASN1("version", ASN1.INTEGER, new ByteString("01", HEX)));
t.add(this.getSignatureAlgorithm());
t.add(this.getIssuer());
t.add(this.getThisUpdate());
if (this.nextUpdate != null) {
t.add(this.getNextUpdate());
}
if (this.revokedCertificates.length > 0) {
t.add(this.getRevokedCertificates());
}
if (this.extensions.length > 0) {
t.add(this.getExtensions());
}
return t;
}
CRLGenerator.prototype.generateCRL = function(privateKey) {
var certlist = new ASN1("certificateList", ASN1.SEQUENCE);
var tbs = this.getTbsCertificateList();
certlist.add(tbs);
certlist.add(this.getSignatureAlgorithm());
var signature = this.crypto.sign(privateKey, this.signatureAlgorithm, tbs.getBytes());
signature = (new ByteString("00", HEX)).concat(signature);
var signatureValue = new ASN1("signatureValue", ASN1.BIT_STRING, signature);
certlist.add(signatureValue);
return certlist;
}
function CRLGeneratorTest() {
var crypto = new Crypto();
var caPrivateKey = new Key();
caPrivateKey.setType(Key.PRIVATE);
var caPublicKey = new Key();
caPublicKey.setType(Key.PUBLIC);
caPublicKey.setSize(1024);
crypto.generateKeyPair(Crypto.RSA, caPublicKey, caPrivateKey);
var x = new CRLGenerator(crypto);
x.reset();
x.setSignatureAlgorithm(Crypto.RSA);
var issuer = [{ C:"UT" },{ O:"ACME Corporation" },{ CN:"Test-CA" }];
x.setIssuer(issuer);
var now = new Date();
x.setThisUpdate(now);
var nextMonth = new Date();
nextMonth.setMonth((now.getMonth() + 1) % 12);
x.setNextUpdate(nextMonth);
x.addAuthorityKeyIdentifierExtension(caPublicKey);
x.addCRLNumberExtension(11);
x.revokeCertificate(new ByteString("01", HEX));
x.revokeCertificate(new ByteString("80", HEX), new Date());
x.revokeCertificate(new ByteString("80", HEX), new Date(), CRLGenerator.keyCompromise);
x.revokeCertificate(new ByteString("80", HEX), new Date(), CRLGenerator.superseded, new ASN1("crlExtensions", ASN1.SEQUENCE));
var crl = x.generateCRL(caPrivateKey);
var fn = GPSystem.mapFilename("crl.crl", GPSystem.USR);
PKIXCommon.writeFileToDisk(fn, crl.getBytes());
print(crl);
var x = new CRLGenerator(crypto);
x.reset();
x.setSignatureAlgorithm(Crypto.RSA);
var issuer = [{ C:"UT" },{ O:"ACME Corporation" },{ CN:"Test-CA" }];
x.setIssuer(issuer);
var now = new Date();
x.setThisUpdate(now);
var nextMonth = new Date();
nextMonth.setMonth((now.getMonth() + 1) % 12);
x.setNextUpdate(nextMonth);
var crlnumber = x.loadCRLEntries(fn);
assert(crlnumber == 11);
x.addAuthorityKeyIdentifierExtension(caPublicKey);
x.addCRLNumberExtension(crlnumber + 1);
x.revokeCertificate(crypto.generateRandom(8), new Date(), CRLGenerator.keyCompromise);
var crl = x.generateCRL(caPrivateKey);
print(crl);
}
Documentation generated by
JSDoc on Tue Apr 15 22:10:49 2025