trustanchor.js
Summary
TrustAnchor Base class for card verifiable certificate based access controller
Class Summary
|
TrustAnchor |
Class implementing a CVC based access controller
|
function TrustAnchor(root) {
if (typeof(root) == "undefined") {
return;
}
this.chain = [];
this.chain.push(root);
this.recentCAROnly = false;
var chat = root.getCHAT();
var id = chat.get(0).value.right(1).toUnsigned();
var name = root.getCHR().getHolder();
FileSystemIdObject.call(this, name, id);
}
TrustAnchor.prototype = new FileSystemIdObject();
TrustAnchor.prototype.constructor = TrustAnchor;
TrustAnchor.TYPE = "TrustAnchor";
TrustAnchor.idIS = new ByteString("id-IS", OID);
TrustAnchor.prototype.getType = function() {
return TrustAnchor.TYPE;
}
TrustAnchor.prototype.addCARforPACE = function(response) {
var cl = this.chain.length;
response.add(new ASN1(0x87, this.chain[cl - 1].getCHR().getBytes()));
if ((cl > 1) && !this.recentCAROnly) {
response.add(new ASN1(0x88, this.chain[cl - 2].getCHR().getBytes()));
}
}
TrustAnchor.prototype.isIssuer = function(chr) {
var cvc = this.getCertificateFor(chr);
return cvc != null;
}
TrustAnchor.prototype.getPublicKeyFor = function(chr) {
var cl = this.chain.length - 1;
for (; (cl >= 0) && !this.chain[cl].getCHR().equals(chr); cl--) {
}
if (cl < 0) {
return null;
}
var i = cl;
if (CVC.isECDSA(this.chain[cl].getPublicKeyOID()) && !this.chain[i].containsDomainParameter()) {
for (cl--; (cl >= 0) && !this.chain[cl].containsDomainParameter(); cl--) {}
if (cl < 0) {
return null;
}
var dp = this.chain[cl].getPublicKey();
return this.chain[i].getPublicKey(dp);
} else {
return this.chain[i].getPublicKey();
}
}
TrustAnchor.prototype.getCertificateFor = function(chr) {
var cl = this.chain.length;
if (this.chain[cl - 1].getCHR().toString() == chr) {
return this.chain[cl - 1];
}
if ((cl > 1) && !this.recentCAROnly) {
if (this.chain[cl - 2].getCHR().toString() == chr) {
return this.chain[cl - 2];
}
}
return null;
}
TrustAnchor.prototype.updateEFCVCA = function(dataProvider) {
var cl = this.chain.length - 1;
var bb = new ByteBuffer();
bb.append((new ASN1(0x42, this.chain[cl].getCHR().getBytes())).getBytes());
if ((cl > 0) && !this.recentCAROnly) {
bb.append((new ASN1(0x42, this.chain[cl - 1].getCHR().getBytes())).getBytes());
}
bb.append(0);
dataProvider.updateEFCVCA(bb.toByteString());
}
TrustAnchor.prototype.checkCertificate = function(issuer, subject, dataProvider, dp) {
if (subject.getCXD().valueOf() < subject.getCED().valueOf()) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Certificate expiration is before effective date");
}
try {
var puk = subject.getPublicKey(dp);
if (puk.getComponent(Key.ECC_QX).length + puk.getComponent(Key.ECC_QY).length != (puk.getComponent(Key.ECC_P).length << 1)) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Invalid public key");
}
}
catch(e) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, e.message);
}
var chatissuer = issuer.getCHAT();
var chatsubject = subject.getCHAT();
var rolesubject = chatsubject.get(0).value;
if (!chatissuer.get(0).value.equals(rolesubject)) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Role mismatch");
}
rightsissuer = chatissuer.get(1).value;
rightssubject = chatsubject.get(1).value;
if (rightsissuer.length != rightssubject.length) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Different size in rights mask of chat");
}
typeissuer = rightsissuer.byteAt(0) & 0xC0;
typesubject = rightssubject.byteAt(0) & 0xC0;
if (typeissuer == 0x40) {
typeissuer = 0x80;
}
if (typesubject == 0x40) {
typesubject = 0x80;
}
if (((typesubject >= typeissuer) && (typeissuer != 0xC0)) ||
((typesubject == 0x00) && (typeissuer == 0xC0))) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Certificate hierachy invalid");
}
if (!issuer.getPublicKeyOID().equals(subject.getPublicKeyOID())) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Public key algorithm mismatch");
}
var date = dataProvider.getDate().valueOf();
if (typesubject != 0xC0) {
if (subject.getCXD().valueOf() < date) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Certificate is expired");
}
} else {
print("Add to chain: " + subject);
this.chain.push(subject);
if (rolesubject.equals(TrustAnchor.idIS)) {
this.updateEFCVCA(dataProvider);
}
}
if ((rightsissuer.byteAt(0) & 0xC0) != 0x40) {
if (subject.getCED().valueOf() > date) {
dataProvider.setDate(subject.getCED());
}
}
}
TrustAnchor.prototype.validateCertificateIssuedByCVCA = function(crypto, cert, dataProvider) {
cc = this.getCertificateFor(cert.getCAR());
puk = this.getPublicKeyFor(cert.getCAR());
if (!puk || !cert.verifyWith(crypto, puk, cc.getPublicKeyOID())) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Could not verify certificate signature");
}
this.checkCertificate(cc, cert, dataProvider, puk);
}
TrustAnchor.prototype.validateCertificateIssuedByDVCA = function(crypto, cert, dvca, dataProvider) {
var dp = this.getPublicKeyFor(dvca.getCAR());
if (!dp || !cert.verifyWith(crypto, dvca.getPublicKey(dp), dvca.getPublicKeyOID())) {
throw new GPError("TrustAnchor", GPError.INVALID_DATA, APDU.SW_INVDATA, "Could not verify certificate signature");
}
this.checkCertificate(dvca, cert, dataProvider, dvca.getPublicKey(dp));
}
Documentation generated by
JSDoc on Tue Sep 3 22:29:41 2013