agreeKey.js
Summary
Agree a common key between two SmartCard-HSM (requires V2.1)
CVC = require("scsh/eac/CVC").CVC;
SmartCardHSM = require("scsh/sc-hsm/SmartCardHSM").SmartCardHSM;
SmartCardHSMKeySpecGenerator = require("scsh/sc-hsm/SmartCardHSM").SmartCardHSMKeySpecGenerator;
HSMKeyStore = require("scsh/sc-hsm/HSMKeyStore").HSMKeyStore;
function Endpoint(readername,name) {
this.card = new Card(readername);
this.crypto = new Crypto();
this.sc = new SmartCardHSM(this.card);
this.ks = new HSMKeyStore(this.sc);
this.ephemeralKeyName = "ephemeralKey:" + name;
var devAutCert = this.sc.readBinary(SmartCardHSM.C_DevAut);
var chain = SmartCardHSM.validateCertificateChain(this.crypto, devAutCert);
if (chain == null) {
throw new GPError("Endpoint", GPError.DEVICE_ERROR, 0, "Card is not a valid SmartCard-HSM");
}
this.chain = chain;
}
Endpoint.prototype.login = function(pin) {
var sw = this.sc.verifyUserPIN(new ByteString(pin, ASCII));
if (sw != 0x9000) {
print(SmartCardHSM.describePINStatus(sw, "User PIN"));
}
return sw == 0x9000;
}
Endpoint.prototype.generateEphemeralKey = function() {
if (this.ks.hasKey(this.ephemeralKeyName)) {
this.ks.deleteKey(this.ephemeralKeyName);
}
var dp = new Key();
dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
var gen = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp);
gen.algorithms = new ByteString("83", HEX);
print("Generating key");
var req = this.ks.generateKeyPair(this.ephemeralKeyName, gen);
var a = new ASN1(0x30);
a.add(req.getASN1());
a.add(this.chain.devicecert.getASN1());
a.add(this.chain.dica.getASN1());
return (a.getBytes());
}
Endpoint.prototype.verifyCertificate = function(publicKey) {
assert(publicKey.byteAt(0) == 0x30, "Not a public key structure");
var a = new ASN1(publicKey);
assert(a.elements == 3, "Must contain three elements");
var dev = new CVC(a.get(1));
var dica = new CVC(a.get(2));
print("Verify certificate");
this.sc.verifyCertificate(dica);
print("Verify certificate");
this.sc.verifyCertificate(dev);
var ext = dev.getExtension(new ByteString("iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) cardcontact(24991) ca(3) extensions(2) 1", OID));
if (ext) {
print("Identity of peer " + ext.get(1).value.toString(UTF8));
}
}
Endpoint.prototype.deriveKey = function(publicKey, deriveParam) {
assert(publicKey.byteAt(0) == 0x30, "Not a public key structure");
var a = new ASN1(publicKey);
assert(a.elements == 3, "Must contain three elements");
print("Derive key");
var prk = this.ks.getKey(this.ephemeralKeyName);
var pub = new CVC(a.get(0));
var car = pub.getOuterCAR().getBytes();
var pukrefdo = new ASN1(0x83, car);
var pukref = pukrefdo.getBytes();
this.sc.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
var tl = new TLVList(pub.getBytes(), TLV.EMV);
var t = tl.index(0);
var pubo = t.getValue();
var cdata = pubo.concat((new ASN1(0x50, deriveParam)).getBytes());
var ss = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, prk.id, 0x83, cdata, 0, [0x9000] );
assert(ss.length == 32, "Shared secret length must be 32 bytes");
return ss;
}
var pin = "648219";
var rl = Card.getReaderList();
if (typeof(r1) != "string") {
var r1 = rl[0];
}
if (typeof(r2) != "string") {
if (rl.length == 1) {
var r2 = r1;
}
var r2 = rl[1];
}
var r1 = Dialog.prompt("Select reader 1", r1, rl);
assert(r1 != null);
var r2 = Dialog.prompt("Select reader 2", r2, rl);
assert(r2 != null);
var ep1 = new Endpoint(r1, "ep1");
var ep2 = new Endpoint(r2, "ep2");
assert(ep1.login(pin), "Login failed");
assert(ep2.login(pin), "Login failed");
pub1 = ep1.generateEphemeralKey();
pub2 = ep2.generateEphemeralKey();
ep1.verifyCertificate(pub2);
ep2.verifyCertificate(pub1);
var deriveParam = new ByteString("Label", ASCII);
var k1 = ep1.deriveKey(pub2, deriveParam);
print("Key on ep1: " + k1);
var k2 = ep2.deriveKey(pub1, deriveParam);
print("Key on ep2: " + k2);
Documentation generated by
JSDoc on Sat Feb 24 15:17:19 2024