      1 /**
      2  *  ---------
      3  * |.##> <##.|  SmartCard-HSM Support Scripts
      4  * |#       #|
      5  * |#       #|  Copyright (c) 2011-2012 CardContact Software & System Consulting
      6  * |'##> <##'|  Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de)
      7  *  ---------
      8  *
      9  *  This file is part of OpenSCDP.
     10  *
     11  *  OpenSCDP is free software; you can redistribute it and/or modify
     12  *  it under the terms of the GNU General Public License version 2 as
     13  *  published by the Free Software Foundation.
     14  *
     15  *  OpenSCDP is distributed in the hope that it will be useful,
     16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  *  GNU General Public License for more details.
     19  *
     20  *  You should have received a copy of the GNU General Public License
     21  *  along with OpenSCDP; if not, write to the Free Software
     22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     23  *
     24  * @fileoverview SmartCard-HSM Card Service
     25  */
     26
     27 // Imports
     28 var CVC = require("scsh/eac/CVC").CVC;
     29 var PublicKeyReference = require("scsh/eac/PublicKeyReference").PublicKeyReference;
     30 var ChipAuthentication = require("scsh/eac/ChipAuthentication").ChipAuthentication;
     31 var PKCS1 = require("scsh/pkcs/PKCS1").PKCS1;
     32 var DKEK = require("scsh/sc-hsm/DKEK").DKEK;
     33 var Bitmap = require("scsh/utils/Bitmap").Bitmap;
     34
     35
     36
     37 /**
     38  * Create a SmartCard-HSM access object
     39  * @class Class implementing support for SmartCard-HSM access
     40  * @constructor
     41  * @param {Card} card the card object
     42  */
     43 function SmartCardHSM(card) {
     44 	this.card = card;
     45
     46 	this.maxCAPDU = 1232;			// APDU buffer limit in JCOP 3
     47 	this.maxRAPDU = 1232;
     48 	this.limitedAPDUTransport = false;	// The APDU transport does not support the full response side
     49
     50 	if (card.readerName.indexOf("Secure Flash Card") == 0) {
     51 		this.maxCAPDU = 478;
     52 		this.maxRAPDU = 506;
     53 		this.limitedAPDUTransport = true;
     54 	} else if (card.readerName.indexOf("REINER SCT cyberJack") == 0) {
     55 		this.maxCAPDU = 1014;
     56 		this.maxRAPDU = 1014;
     57 		this.limitedAPDUTransport = true;
     58 	} else if (card.readerName.indexOf("ACS APG8201") == 0) {
     59 		this.maxCAPDU = 1141;
     60 		this.maxRAPDU = 1141;
     61 		this.limitedAPDUTransport = true;
     62 	} else if (card.readerName.indexOf("Gemalto IDBridge") == 0) {
     63 		this.maxCAPDU = 262;
     64 		this.maxRAPDU = 499;
     65 		this.limitedAPDUTransport = true;
     66 	}
     67
     68 	if (typeof(this.card.maxReaderCAPDU) != "undefined") {
     69 		if (this.card.maxReaderCAPDU < this.maxCAPDU) {
     70 			this.maxCAPDU = this.card.maxReaderCAPDU;
     71 			this.limitedAPDUTransport = true;
     72 		}
     73 	}
     74
     75 	if (typeof(this.card.maxReaderRAPDU) != "undefined") {
     76 		if (this.card.maxReaderRAPDU < this.maxRAPDU) {
     77 			this.maxRAPDU = this.card.maxReaderRAPDU;
     78 			this.limitedAPDUTransport = true;
     79 		}
     80 	}
     81
     82 	// 9 Byte CLA|INS|P1|P2|LcEx||LeEx
     83 	// 19 Byte SM overhead (Tag 85, 3 byte length, 1 byte padding indicator, tag 97 02 <Le> and tag 8E 08 <mac>
     84 	// 1 byte required for padding
     85 	this.maxCData = Math.floor((this.maxCAPDU - 9 - 19) / 16) * 16 - 1;
     86 //	print("maxCData=" + this.maxCData);
     87
     88 	// 19 Byte SM overhead (Tag 85, 3 byte length, 1 byte padding indicator, tag 99 02 SW1SW2 and tag 8E 08 <mac>
     89 	// 2 byte SW1/SW2
     90 	// 1 byte required for padding
     91 	this.maxRData = Math.floor((this.maxRAPDU - 18 - 2) / 16) * 16 - 1;
     92 //	print("maxRData=" + this.maxRData);
     93
     94 	this.useExternalHashInECDSA = false;	// Disable hashing in card if affected by bug #93
     95
     96 	// Check if SmartCard-HSM is already selected and authenticated
     97 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81, 0);
     98
     99 	if (this.card.SW != 0x9000) {
    100 		this.logout();		// Select application
    101 	}
    102
    103 	this.namemap = [];
    104 	this.idmap = [];
    105 }
    106
    107 exports.SmartCardHSM = SmartCardHSM;
    108
    109
    110 SmartCardHSM.C_DevAut = new ByteString("2F02", HEX);
    111 SmartCardHSM.EF_TokenInfo = new ByteString("2F03", HEX);
    112 SmartCardHSM.EF_StaticTokenInfo = new ByteString("CB00", HEX);
    113
    114 SmartCardHSM.PrK_DevAut = 0;
    115 SmartCardHSM.PIN_User = 0x81;
    116
    117 SmartCardHSM.PRKDPREFIX = 0xC4;
    118 SmartCardHSM.KDDPREFIX = 0xC7;
    119 SmartCardHSM.CERTDPREFIX = 0xC8;
    120 SmartCardHSM.DODPREFIX = 0xC9;
    121 SmartCardHSM.CACERTIFICATEPREFIX = 0xCA;
    122 SmartCardHSM.KEYMETAPREFIX = 0xCB;	// Changed in V2.3
    123 SmartCardHSM.READONLYDATAPREFIX = 0xCB;	// Starting with V2.3
    124 SmartCardHSM.KEYPREFIX = 0xCC;
    125 SmartCardHSM.CONFIDENTIALDATAPREFIX = 0xCD;
    126 SmartCardHSM.EECERTIFICATEPREFIX = 0xCE;
    127 SmartCardHSM.PUBLICDATAPREFIX = 0xCF;
    128
    129 SmartCardHSM.ALGORITHMS = [];
    130
    131 // Symmetric
    132 SmartCardHSM.ALG_CBC_ENC = 0x10;
    133 SmartCardHSM.ALG_CBC_DEC = 0x11;
    134 SmartCardHSM.ALG_CMAC = 0x18;
    135
    136 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_CBC_ENC] = "CBC_ENC";
    137 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_CBC_DEC] = "CBC_DEC";
    138 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_CMAC] = "CMAC";
    139
    140
    141 // RSA Block
    142 SmartCardHSM.ALG_RSA_SIGN_RAW = 0x20;
    143 SmartCardHSM.ALG_RSA_DECRYPT_RAW = 0x21;
    144 SmartCardHSM.ALG_RSA_DECRYPT_V15 = 0x22;
    145 SmartCardHSM.ALG_RSA_DECRYPT_OAEP = 0x23;
    146
    147 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_RAW] = "RSA_RAW";
    148 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_DECRYPT_RAW] = "RSA_DECRYPT_RAW";
    149 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_DECRYPT_V15] = "RSA_DECRYPT_V15";
    150 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_DECRYPT_OAEP] = "RSA_DECRYPT_OAEP";
    151
    152
    153 // RSA Sign with hash and PKCS#1 V1.5
    154 SmartCardHSM.ALG_RSA_SIGN_V15_SHA1 = 0x31;
    155 SmartCardHSM.ALG_RSA_SIGN_V15_SHA256 = 0x33;
    156 SmartCardHSM.ALG_RSA_SIGN_V15_SHA512 = 0x35;
    157
    158 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_V15_SHA1] = "RSA_V15_SHA1";
    159 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_V15_SHA256] = "RSA_V15_SHA256";
    160 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_V15_SHA512] = "RSA_V15_SHA512";
    161
    162
    163 // RSA Sign with hash and PSS
    164 SmartCardHSM.ALG_RSA_SIGN_PSS = 0x40;
    165 SmartCardHSM.ALG_RSA_SIGN_PSS_SHA1 = 0x41;
    166 SmartCardHSM.ALG_RSA_SIGN_PSS_SHA256 = 0x43;
    167 SmartCardHSM.ALG_RSA_SIGN_PSS_SHA512 = 0x45;
    168
    169 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_PSS] = "RSA_PSS";
    170 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_PSS_SHA1] = "RSA_PSS_SHA1";
    171 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_PSS_SHA256] = "RSA_PSS_SHA256";
    172 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_RSA_SIGN_PSS_SHA512] = "RSA_PSS_SHA512";
    173
    174
    175 // ECDSA
    176 SmartCardHSM.ALG_ECDSA = 0x70;
    177 SmartCardHSM.ALG_ECDSA_SHA1 = 0x71;
    178 SmartCardHSM.ALG_ECDSA_SHA224 = 0x72;
    179 SmartCardHSM.ALG_ECDSA_SHA256 = 0x73;
    180 SmartCardHSM.ALG_ECDSA_SHA384 = 0x74;
    181 SmartCardHSM.ALG_ECDSA_SHA512 = 0x75;
    182
    183 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA] = "ECDSA";
    184 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA1] = "ECDSA_SHA1";
    185 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA224] = "ECDSA_SHA224";
    186 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA256] = "ECDSA_SHA256";
    187 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA384] = "ECDSA_SHA384";
    188 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDSA_SHA512] = "ECDSA_SHA512";
    189
    190
    191 // ECDH
    192 SmartCardHSM.ALG_ECDH = 0x80;
    193 SmartCardHSM.ALG_ECDHAutPuk = 0x83;
    194 SmartCardHSM.ALG_ECDHXKEK = 0x84;
    195
    196 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDH] = "ECDH";
    197 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDHAutPuk] = "ECDH_AUTPUK";
    198 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_ECDHXKEK] = "ECDH_XKEK";
    199
    200
    201 // Wrap
    202 SmartCardHSM.ALG_WRAP = 0x92;
    203 SmartCardHSM.ALG_UNWRAP = 0x93;
    204 SmartCardHSM.ALG_REPLACE = 0x94;
    205
    206 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_WRAP] = "WRAP";
    207 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_UNWRAP] = "UNWRAP";
    208 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_REPLACE] = "REPLACE";
    209
    210
    211 // Derive
    212 SmartCardHSM.ALG_DERIVE_EC_KEY = 0x98;
    213 SmartCardHSM.ALG_DERIVE_SP800_56C = 0x99;
    214
    215 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_DERIVE_EC_KEY] = "DERIVE_EC";
    216 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_DERIVE_SP800_56C] = "DERIVE_SP800_56C";
    217
    218
    219 SmartCardHSM.ALG_SIGN_DEFAULT = 0xA0;
    220 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_SIGN_DEFAULT] = "SIGN_DEFAULT";
    221
    222
    223 // Key Generation
    224 SmartCardHSM.ALG_GENERATE_AES128 = 0xB0;
    225 SmartCardHSM.ALG_GENERATE_AES192 = 0xB1;
    226 SmartCardHSM.ALG_GENERATE_AES256 = 0xB2;
    227
    228 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_GENERATE_AES128] = "GENERATE_AES128";
    229 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_GENERATE_AES192] = "GENERATE_AES192";
    230 SmartCardHSM.ALGORITHMS[SmartCardHSM.ALG_GENERATE_AES256] = "GENERATE_AES256";
    231
    232
    233 SmartCardHSM.ALGOMAP = {};
    234 for (var i = 0; i < SmartCardHSM.ALGORITHMS.length; i++) {
    235 	var name = SmartCardHSM.ALGORITHMS[i];
    236 	if (typeof(name) != "undefined") {
    237 		SmartCardHSM.ALGOMAP[name] = i;
    238 	}
    239 }
    240
    241
    242 SmartCardHSM.rootCerts = {
    243 	DESRCACC100001: new CVC(new ByteString(" ", HEX)),
    244 	UTSRCACC100001: new CVC(new ByteString(" ", HEX))
    245 }
    246
    247 SmartCardHSM.devAutPuk = new Key();
    248 SmartCardHSM.devAutPuk.setType(Key.PUBLIC);
    249 SmartCardHSM.devAutPuk.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
    250 SmartCardHSM.devAutPuk.setComponent(Key.ECC_QX, new ByteString("4C01EA36C5065FF47E8F0676A77CDCED6C8F745E6784F7807F5520124F81ED05", HEX));
    251 SmartCardHSM.devAutPuk.setComponent(Key.ECC_QY, new ByteString("4112DCE471CA003442830A10C75B31F9BFADD60628F47131628C7254AD8B956A", HEX));
    252
    253
    254
    255 /**
    256  * Remove Root Certificate of Development SRCA
    257  *
    258  * Always call this on a productive system
    259  */
    260 SmartCardHSM.disableUTSRCA = function() {
    261 	delete SmartCardHSM.rootCerts.UTSRCACC100001;
    262 }
    263
    264
    265
    266 /**
    267  * Set the list of trusted SRCA certificates
    268  *
    269  * @param {ByteString[]} srcalist the list of binary encoded SRCA certificates
    270  */
    271 SmartCardHSM.setTrustedSRCACertificates = function(srcalist) {
    272 	SmartCardHSM.rootCerts = {};
    273 	for (var i = 0; i < srcalist.length; i++) {
    274 		var cert = new CVC(srcalist[i]);
    275 		GPSystem.log(GPSystem.DEBUG, module.id, "Adding as trusted SRCA certificate : " + cert);
    276 		SmartCardHSM.rootCerts[cert.getCHR().toString()] = cert;
    277 	}
    278 }
    279
    280
    281
    282 /**
    283  * Parse list of CVC in a binary blob
    284  *
    285  * @param {ByteString} a binary blob (e.g an EF) containing concatenated CVCs
    286  * @type CVC[]
    287  * @return the list of CVCs
    288  */
    289 SmartCardHSM.parseCertificateList = function(bin) {
    290 	var a = new ASN1((new ASN1(0x30, bin)).getBytes());
    291 	var list = [];
    292 	for (var i = 0; i < a.elements; i++) {
    293 		try	{
    294 			var cvc = new CVC(a.get(i));
    295 			list.push(cvc);
    296 		}
    297 		catch(e) {
    298 			print("Index " + i + " is not a CVC");
    299 			print(a.get(i));
    300 		}
    301 	}
    302 	return list;
    303 }
    304
    305
    306
    307 /**
    308  * Validate device certificate chain
    309  *
    310  * @param {Crypto} crypto the crypto provider to use
    311  * @param {ByteString} devAutCert the device certificate chain read from EF.C_DevAut
    312  * @type Key
    313  * @return the device authentication public key
    314  */
    315 SmartCardHSM.validateCertificateChain = function(crypto, devAutCert) {
    316 	// Device device certificate
    317 	var cvc = new CVC(devAutCert);
    318 	GPSystem.log(GPSystem.DEBUG, module.id, "Device Certificate    : " + cvc);
    319
    320 	if (cvc.getCAR().toString() == "DECA00001") {		// CA used for development version up to 0.17
    321 		if (typeof(SmartCardHSM.rootCerts.UTSRCACC100001) == "undefined") {
    322 			GPSystem.log(GPSystem.DEBUG, module.id, "Device certificate DECA00001 disabled");
    323 			return null;
    324 		}
    325 		if (!cvc.verifyWith(crypto, SmartCardHSM.devAutPuk)) {
    326 			GPSystem.log(GPSystem.DEBUG, module.id, "Device certificate verification failed for CAR=DECA00001");
    327 			return null;
    328 		}
    329 		var path = "/" + cvc.getCAR().getHolder() + "/" + cvc.getCHR().getHolder();
    330 		return { devicecert: cvc, publicKey:cvc.getPublicKey(), path:path };
    331 	}
    332
    333 	// Decode device issuer certificate
    334 	var len = cvc.getASN1().size;
    335 	var cvc = new CVC(devAutCert.left(len));
    336 	var dica = new CVC(devAutCert.bytes(len));
    337 	GPSystem.log(GPSystem.DEBUG, module.id, "Device Issuer CA      : " + dica);
    338
    339 	if (typeof(SmartCardHSM.rootCerts[dica.getCAR()]) == "undefined") {
    340 		GPSystem.log(GPSystem.DEBUG, module.id, "Unknown or disabled root CA " + dica.getCAR());
    341 		return null;
    342 	}
    343
    344 	// Determine root certificateSmartCardHSM.rootCerts[dica.getCAR()]
    345 	var srca = SmartCardHSM.rootCerts[dica.getCAR()];
    346 	GPSystem.log(GPSystem.DEBUG, module.id, "SmartCard-HSM Root CA : " + srca);
    347
    348 	// Validate chain
    349 	var srcapuk = srca.getPublicKey();
    350 	var oid = srca.getPublicKeyOID();
    351 	if (!dica.verifyWith(crypto, srcapuk, oid)) {
    352 		GPSystem.log(GPSystem.DEBUG, module.id, "DICA certificate not verified");
    353 		return null;
    354 	}
    355
    356 	var dicapuk = dica.getPublicKey(srcapuk);
    357 	if (!cvc.verifyWith(crypto, dicapuk, oid)) {
    358 		GPSystem.log(GPSystem.DEBUG, module.id, "Device certificate verification failed");
    359 		return null;
    360 	}
    361
    362 	var path = "/" + srca.getCHR().getHolder() + "/" + dica.getCHR().getHolder() + "/" + cvc.getCHR().getHolder();
    363 	return { srca: srca, dica: dica, devicecert: cvc, publicKey:cvc.getPublicKey(srcapuk), path:path };
    364 }
    365
    366
    367
    368 /**
    369  * Decode algorithm list and return string array with names
    370  *
    371  * @param {ByteString} list the algorithm list, e.g. as returned in the key meta data
    372  * @type String[]
    373  * @return the list of algorithm names
    374  */
    375 SmartCardHSM.decodeAlgorithmList = function(list) {
    376 	var a = [];
    377 	for (var i = 0; i < list.length; i++) {
    378 		a.push(SmartCardHSM.ALGORITHMS[list.byteAt(i)]);
    379 	}
    380
    381 	return a;
    382 }
    383
    384
    385
    386 /**
    387  * Parse and encode the algorithm list containing either algorithm ids or names
    388  *
    389  * @param {String | String[]} list the list of algorithms
    390  * @type ByteString
    391  * @return the algorithm list
    392  */
    393 SmartCardHSM.encodeAlgorithmList = function(list) {
    394 	if (typeof(list) == "string") {
    395 		if (list.indexOf(".") != -1) {
    396 			list = list.split(".");
    397 		} else {
    398 			list = list.split(",");
    399 		}
    400 	}
    401
    402 	var bb = new ByteBuffer();
    403
    404 	for (var i = 0; i < list.length; i++) {
    405 		var e = list[i].trim();
    406 		var id = NaN;
    407 		if (e.length == 2) {
    408 			id = parseInt(e, 16);
    409 		}
    410 		if (isNaN(id)) {
    411 			var id = SmartCardHSM.ALGOMAP[e.toUpperCase()];
    412 			if (typeof(id) == "undefined") {
    413 				print("Unknown keyword or number " + list[i]);
    414 				return null;
    415 			}
    416 		}
    417 		bb.append(id);
    418 	}
    419
    420 	return bb.toByteString();
    421 }
    422
    423
    424
    425 /**
    426  * Return a string describing the SmartCard-HSM Version
    427  *
    428  * @type String
    429  * @return the version string
    430  */
    431 SmartCardHSM.prototype.getVersionInfo = function() {
    432 	if (typeof(this.major) == "undefined") {
    433 		return "Version unknown";
    434 	}
    435
    436 	var str = "Version " + this.major + "." + this.minor;
    437
    438 	if (typeof(this.platform) != "undefined") {
    439 		switch(this.platform) {
    440 			case 0: str += " on JCOP"; break;
    441 			case 1: str += " Demo on JCOP"; break;
    442 			case 2: str += " on JCOP 2.4.1r3"; break;
    443 			case 3: str += " on JCOP 2.4.2r3"; break;
    444 			case 4: str += " on JCOP 2.4.2r1"; break;
    445 			case 5: str += " on JCOP 3"; break;
    446 			case 6: str += " on JCOP 4"; break;
    447 			case 7: str += " on JCOP 4.5"; break;
    448 		}
    449 	}
    450 	return str;
    451 }
    452
    453
    454
    455 /**
    456  * Return the native OCF SmartCardHSMCardService
    457  *
    458  * @type de.cardcontact.opencard.service.smartcardhsm.SmartCardHSMCardService
    459  * @return the OCF SmartCardHSMCardService
    460  */
    461 SmartCardHSM.prototype.getNativeCardService = function() {
    462 	if (this.nativeCardService) {
    463 		return this.nativeCardService;
    464 	}
    465 	this.nativeCardService = this.card.getCardService("de.cardcontact.opencard.service.smartcardhsm.SmartCardHSMCardService");
    466
    467 	return this.nativeCardService;
    468 }
    469
    470
    471
    472 /**
    473  * Validate device certificate chain
    474  *
    475  * @param {Crypto} crypto the crypto provider to use
    476  * @type Key
    477  * @return the device authentication public key
    478  */
    479 SmartCardHSM.prototype.validateCertificateChain = function(crypto) {
    480 	// Read concatenation of both certificates
    481 	var devAutCert = this.readBinary(SmartCardHSM.C_DevAut);
    482 	var chain = SmartCardHSM.validateCertificateChain(crypto, devAutCert);
    483 	if (chain == null) {
    484 		return null;
    485 	}
    486 	return chain.publicKey;
    487 }
    488
    489
    490
    491 /**
    492  * Open a secure channel using device authentication
    493  *
    494  * @param {Crypto} crypto the crypto provider to use
    495  * @param {Key} devAuthPK the device authentication public key
    496  * @param {Number} Key.AES or Key.DES to request AES or DES secure messaging (Default probe)
    497  * @type ISOSecureChannel
    498  * @return the initialized secure channel
    499  */
    500 SmartCardHSM.prototype.openSecureChannel = function(crypto, devAuthPK, smtype) {
    501
    502 	var type;
    503
    504 	if (smtype) {
    505 		type = smtype;
    506 	} else {
    507 		type = Key.AES;
    508 	}
    509
    510 	if (type == Key.DES) {
    511 		var protocol = new ByteString("id-CA-ECDH-3DES-CBC-CBC", OID);
    512 	} else {
    513 		var protocol = new ByteString("id-CA-ECDH-AES-CBC-CMAC-128", OID);
    514 	}
    515
    516 	// Try AES first and fallback to DES is not supported by card
    517
    518 	var bb = new ByteBuffer();
    519 	bb.append(new ASN1(0x80, protocol).getBytes());
    520
    521 	this.card.sendSecMsgApdu(Card.CPRO|Card.CENC|Card.RPRO, 0x00, 0x22, 0x41, 0xA4, bb.toByteString(), [0x9000, 0x6A80]);
    522
    523 	if (this.card.SW == 0x6A80) {
    524 		if (smtype) {
    525 			throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 3, "Requested secure messaging not supported");
    526 		}
    527
    528 		type = Key.DES;
    529
    530 		var protocol = new ByteString("id-CA-ECDH-3DES-CBC-CBC", OID);
    531
    532 		var bb = new ByteBuffer();
    533 		bb.append(new ASN1(0x80, protocol).getBytes());
    534
    535 		this.card.sendSecMsgApdu(Card.CPRO|Card.CENC|Card.RPRO, 0x00, 0x22, 0x41, 0xA4, bb.toByteString(), [0x9000]);
    536 	}
    537
    538 	var ca = new ChipAuthentication(crypto, protocol, devAuthPK);	// For domain parameter
    539 	ca.noPadding = true;
    540 	ca.generateEphemeralCAKeyPair();
    541
    542 	var ephemeralPublicKeyIfd = ca.getEphemeralPublicKey();
    543
    544 	var dado = new ASN1(0x7C, new ASN1(0x80, ephemeralPublicKeyIfd));
    545
    546 	var dadobin = this.card.sendSecMsgApdu(Card.CPRO|Card.CENC|Card.RPRO|Card.RENC, 0x00, 0x86, 0x00, 0x00, dado.getBytes(), 0, [0x9000]);
    547
    548 //	GPSystem.log(GPSystem.DEBUG, module.id, dadobin);
    549
    550 	var dado = new ASN1(dadobin);
    551 	assert(dado.tag == 0x7C);
    552 	assert(dado.elements == 2);
    553 	var nonceDO = dado.get(0);
    554 	assert(nonceDO.tag == 0x81);
    555 	var nonce = nonceDO.value;
    556
    557 	var authTokenDO = dado.get(1);
    558 	assert(authTokenDO.tag == 0x82);
    559 	var authToken = authTokenDO.value;
    560
    561 	var enc = new ByteString("04", HEX);
    562 	enc = enc.concat(devAuthPK.getComponent(Key.ECC_QX));
    563 	enc = enc.concat(devAuthPK.getComponent(Key.ECC_QY));
    564
    565 	GPSystem.log(GPSystem.DEBUG, module.id, "Encoded CA public key: " + enc);
    566 	ca.performKeyAgreement(enc, nonce);
    567 	var result = ca.verifyAuthenticationToken(authToken);
    568
    569 	if (!result) {
    570 		GPSystem.log(GPSystem.DEBUG, module.id, "Authentication token invalid");
    571 		throw new Error("Authentication token invalid");
    572 	}
    573 	GPSystem.log(GPSystem.DEBUG, module.id, "Authentication token valid");
    574
    575 	if (type == Key.DES) {
    576 		var sm = new IsoSecureChannel(crypto);
    577 		sm.setEncKey(ca.kenc);
    578 		sm.setMacKey(ca.kmac);
    579 		sm.setMACSendSequenceCounter(new ByteString("0000000000000000", HEX));
    580 	} else {
    581 		var sm = new IsoSecureChannel(crypto, IsoSecureChannel.SSC_SYNC_ENC_POLICY);
    582 		sm.setEncKey(ca.kenc);
    583 		sm.setMacKey(ca.kmac);
    584 		sm.setMACSendSequenceCounter(new ByteString("00000000000000000000000000000000", HEX));
    585 	}
    586
    587 	this.card.setCredential(sm);
    588 	this.smactive = true;
    589 	return sm;
    590 }
    591
    592
    593
    594 /**
    595  * Update transparent EF referenced by file identifier
    596  *
    597  * @param {ByteString} fid the two byte file identifier
    598  * @param {Number} offset the offset into the EF
    599  * @param {ByteString} data the data to write
    600  */
    601 SmartCardHSM.prototype.updateBinary = function(fid, offset, data) {
    602 	if (typeof(offset) == "undefined") {
    603 		offset = 0;
    604 	}
    605
    606 	var bytesLeft = data.length;
    607 	var sent = 0;
    608
    609 	// 8 bytes are required for T54(4) and T53(4)
    610 	var blksize = this.maxCData - 8;
    611
    612 	while (bytesLeft > 0) {
    613 		var toSend = bytesLeft >= blksize ? blksize : bytesLeft;
    614
    615 		var t54 = new ASN1(0x54, ByteString.valueOf(offset, 2));
    616 		var t53 = new ASN1(0x53, data.bytes(sent, toSend));
    617
    618 		var cdata = t54.getBytes().concat(t53.getBytes());
    619 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, fid.byteAt(0), fid.byteAt(1), cdata, [0x9000]);
    620
    621 		bytesLeft -= toSend;
    622 		offset += toSend;
    623 		sent += toSend;
    624 	}
    625 }
    626
    627
    628
    629 /**
    630  * Read transparent EF referenced by file identifier
    631  *
    632  * @param {ByteString} fid the two byte file identifier (optional - use currently selected EF if absent)
    633  * @param {Number} offset the offset into the EF (optional)
    634  * @param {Number} length the number of byte to read (optional)
    635  * @type ByteString
    636  * @return the data read from the EF
    637  */
    638 SmartCardHSM.prototype.readBinary = function(fid, offset, length) {
    639 	if (typeof(offset) == "undefined") {
    640 		offset = 0;
    641 	}
    642 	if (typeof(fid) == "undefined") {
    643 		fid = new ByteString("0000", HEX);
    644 	}
    645
    646 	var rsp = new ByteBuffer();
    647 	do	{
    648 		var t54 = new ASN1(0x54, ByteString.valueOf(offset, 2));
    649
    650 		if (length || this.limitedAPDUTransport || this.smactive) {				// Is a length defined ?
    651 			var le = (!length || (length > this.maxRData)) ? this.maxRData: length;		// Truncate if larger than maximum APDU size ?
    652 		} else {
    653 			var le = this.maxRAPDU <= 256 ? 0 : 65536;					// Get all with Le=0 in either short or extended APDU mode
    654 		}
    655
    656 		var data = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xB1, fid.byteAt(0), fid.byteAt(1), t54.getBytes(), le, [0x9000, 0x6282]);
    657
    658 		if (data.length == 0) {
    659 			break;
    660 		}
    661
    662 		rsp.append(data);
    663 		offset += data.length;
    664
    665 		if (length) {					// Length was defined, see if we already got everything
    666 			length -= data.length;
    667 			if (length <= 0) {
    668 				break;
    669 			}
    670 		}
    671 	} while ((this.card.SW == 0x9000) || (this.card.SW == 0x6282));
    672
    673 	return rsp.toByteString();
    674 }
    675
    676
    677
    678 /**
    679  * Select the file or key an return the FCP
    680  *
    681  * @param {ByteString} fid the two byte file object identifier
    682  */
    683 SmartCardHSM.prototype.selectFile = function(fid) {
    684 	var fcp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xA4, 0x00, 0x04, fid, 0, [0x9000]);
    685 	return fcp;
    686 }
    687
    688
    689
    690 /**
    691  * Try selecting the file to see if is present
    692  *
    693  * @param {ByteString} fid the two byte file object identifier
    694  */
    695 SmartCardHSM.prototype.hasFile = function(fid) {
    696 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xA4, 0x00, 0x04, fid, 0);
    697 	return this.card.SW == 0x9000;
    698 }
    699
    700
    701
    702 /**
    703  * Delete file system object (EF or key)
    704  *
    705  * @param {ByteString} fid the two byte file object identifier
    706  */
    707 SmartCardHSM.prototype.deleteFile = function(fid) {
    708 	return this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xE4, 0x02, 0x00, fid, [0x9000]);
    709 }
    710
    711
    712
    713 /**
    714  * Strips leading zeros of a ByteString
    715  *
    716  * @param {ByteString} value the ByteString value
    717  * @return the stripped ByteString object, may be an empty ByteString
    718  * @type ByteString
    719  */
    720 SmartCardHSM.stripLeadingZeros = function(value) {
    721 	var i = 0;
    722 	for (; (i < value.length) && (value.byteAt(i) == 0); i++);
    723
    724 	return value.right(value.length - i);
    725 }
    726
    727
    728
    729 /**
    730  * Build input for Generate Asymmetric Key Pair command for generating an ECC key pair
    731  *
    732  * @param {PublicKeyReference} innerCAR the CA the request shall be directed to
    733  * @param {ByteString} algo the public key algorithm
    734  * @param {PublicKeyReference} chr the certificate holder reference associated with this key
    735  * @param {Key} dp the domain parameter for the key
    736  * @param {PublicKeyReference} outerCAR the certificate holder reference of the public key for verifying the outer signature
    737  * @param {Key} privateKey optional parameter to supply a private key value for import. This only works with the development version
    738  *              of the SmartCard-HSM.
    739  * @type ByteString
    740  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
    741  */
    742 SmartCardHSM.buildGAKPwithECC = function(innerCAR, algo, chr, dp, outerCAR, priKey) {
    743
    744 	// Encode G
    745 	var bb = new ByteBuffer();
    746 	// uncompressed encoding
    747 	bb.append(new ByteString("04", HEX));
    748 	bb.append(dp.getComponent(Key.ECC_GX));
    749 	bb.append(dp.getComponent(Key.ECC_GY));
    750 	var G = bb.toByteString();
    751
    752 	var t = new ASN1(0x30,
    753 				new ASN1("CPI", 0x5F29, new ByteString("00", HEX)),
    754 				new ASN1("CAR", 0x42, innerCAR.getBytes()),
    755 				new ASN1("Public Key", 0x7F49,
    756 					new ASN1("Object Identifier", 0x06, algo),
    757 					new ASN1("Prime Modulus", 0x81, dp.getComponent(Key.ECC_P)),
    758 					new ASN1("First coefficient a", 0x82, dp.getComponent(Key.ECC_A)),
    759 					new ASN1("Second coefficient b", 0x83, dp.getComponent(Key.ECC_B)),
    760 					new ASN1("Base Point G", 0x84, G),
    761 					new ASN1("Order of the base point", 0x85, dp.getComponent(Key.ECC_N)),
    762 					new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(dp.getComponent(Key.ECC_H)))
    763 				),
    764 				new ASN1("CHR", 0x5F20, chr.getBytes())
    765 			);
    766
    767 	if (typeof(outerCAR) != "undefined") {
    768 		t.add(new ASN1("OuterCAR", 0x45, outerCAR.getBytes()));
    769 	}
    770
    771 	if (priKey != undefined) {
    772 		var d = new ASN1("Private Key", 0x8A, priKey.getComponent(Key.ECC_D));
    773 		t.get(2).add(d);
    774 //		GPSystem.log(GPSystem.DEBUG, module.id, t);
    775 	}
    776 	return t.value;
    777 }
    778
    779
    780
    781 /**
    782  * Build input for Generate Asymmetric Key Pair command for generating a RSA key pair
    783  *
    784  * @param {PublicKeyReference} innerCAR the CA the request shall be directed to
    785  * @param {ByteString} algo the public key algorithm
    786  * @param {PublicKeyReference} chr the certificate holder reference associated with this key
    787  * @param {Number} keysize the module size in bits (1024, 1536 or 2048)
    788  * @param {PublicKeyReference} outerCAR the certificate holder reference of the public key for verifying the outer signature
    789  * @type ByteString
    790  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
    791  */
    792 SmartCardHSM.buildGAKPwithRSA = function(innerCAR, algo, chr, keysize, outerCAR) {
    793
    794 	var t = new ASN1(0x30,
    795 				new ASN1("CPI", 0x5F29, new ByteString("00", HEX)),
    796 				new ASN1("CAR", 0x42, innerCAR.getBytes()),
    797 				new ASN1("Public Key", 0x7F49,
    798 					new ASN1("Object Identifier", 0x06, algo),
    799 					new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)),
    800 					new ASN1("Key Size", 0x02, ByteString.valueOf(keysize))
    801 				),
    802 				new ASN1("CHR", 0x5F20, chr.getBytes())
    803 			);
    804
    805 	if (typeof(outerCAR) != "undefined") {
    806 		t.add(new ASN1("OuterCAR", 0x45, outerCAR.getBytes()));
    807 	}
    808 	return t.value;
    809 }
    810
    811
    812
    813 /**
    814  * Create a PKCS#15 PrivateECCKey description
    815  *
    816  * @param {Number/ByteString} keyid the key identifier
    817  * @param {String} label the key label
    818  * @type ASN1
    819  * @return the PrivateECCKey description
    820  */
    821 SmartCardHSM.buildPrkDforECC = function(keyid, label, keysize) {
    822 	if (typeof(keyid) == "number") {
    823 		keyid = ByteString.valueOf(keyid);
    824 	}
    825
    826 	var prkd = 	new ASN1(0xA0,
    827 					new ASN1(ASN1.SEQUENCE,
    828 						new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
    829 //						new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)),
    830 //						new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX))
    831 					),
    832 					new ASN1(ASN1.SEQUENCE,
    833 						new ASN1(ASN1.OCTET_STRING, keyid),
    834 						new ASN1(ASN1.BIT_STRING, new ByteString("072080", HEX))
    835 					),
    836 					new ASN1(0xA1,
    837 						new ASN1(ASN1.SEQUENCE,
    838 							new ASN1(ASN1.SEQUENCE,
    839 								new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX))
    840 							)
    841 						)
    842 					)
    843 				);
    844
    845 	if (keysize != undefined) {
    846 		assert(keysize > 0, "Key size must be > 0");
    847 		var tlvint = ByteString.valueOf(keysize);
    848 		if (tlvint.byteAt(0) >= 0x80) {
    849 			tlvint = (new ByteString("00", HEX)).concat(tlvint);
    850 		}
    851 		prkd.get(2).get(0).add(new ASN1(ASN1.INTEGER, tlvint));
    852 	}
    853
    854 //	GPSystem.log(GPSystem.DEBUG, module.id, prkd);
    855 	return prkd;
    856 }
    857
    858
    859
    860 /**
    861  * Create a PKCS#15 PrivateRSAKey description
    862  *
    863  * @param {Number/ByteString} keyid the key identifier
    864  * @param {String} label the key label
    865  * @param {Number} modulussize
    866  * @type ASN1
    867  * @return the PrivateECCKey description
    868  */
    869 SmartCardHSM.buildPrkDforRSA = function(keyid, label, modulussize) {
    870 	if (typeof(keyid) == "number") {
    871 		keyid = ByteString.valueOf(keyid);
    872 	}
    873
    874 	var prkd = 	new ASN1(0x30,
    875 					new ASN1(ASN1.SEQUENCE,
    876 						new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
    877 //						new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)),
    878 //						new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX))
    879 					),
    880 					new ASN1(ASN1.SEQUENCE,
    881 						new ASN1(ASN1.OCTET_STRING, keyid),
    882 						new ASN1(ASN1.BIT_STRING, new ByteString("0274", HEX))
    883 					),
    884 					new ASN1(0xA1,
    885 						new ASN1(ASN1.SEQUENCE,
    886 							new ASN1(ASN1.SEQUENCE,
    887 								new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX))
    888 							),
    889 							new ASN1(ASN1.INTEGER, ByteString.valueOf(modulussize))
    890 						)
    891 					)
    892 				);
    893 //	GPSystem.log(GPSystem.DEBUG, module.id, prkd);
    894 	return prkd;
    895 }
    896
    897
    898
    899 /**
    900  * Create a PKCS#15 SecretKey description
    901  *
    902  * @param {Number/ByteString} keyid the key identifier
    903  * @param {String} label the key label
    904  * @param {Number} keysize
    905  * @type ASN1
    906  * @return the secret key description
    907  */
    908 SmartCardHSM.buildSKDforAES = function(keyid, label, keysize) {
    909 	if (typeof(keyid) == "number") {
    910 		keyid = ByteString.valueOf(keyid);
    911 	}
    912
    913 	var skd =
    914 		new ASN1(0xA8,
    915 			// CommonObjectAttributes
    916 			new ASN1(ASN1.SEQUENCE,
    917 				new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
    918 				//						new ASN1(ASN1.BIT_STRING, new ByteString("0780", HEX)),
    919 				//						new ASN1(ASN1.OCTET_STRING, new ByteString("01", HEX))
    920 			),
    921 			// ClassAttributes: CommonKeyAttributes
    922 			new ASN1(ASN1.SEQUENCE,
    923 				new ASN1(ASN1.OCTET_STRING, keyid),
    924 				new ASN1(ASN1.BIT_STRING, new ByteString("07C010", HEX))
    925 			),
    926 			// SubClassAttribute: CommonSecretKeyAttributes
    927 			new ASN1(0xA0,
    928 				new ASN1(ASN1.SEQUENCE,
    929 					new ASN1(ASN1.INTEGER, ByteString.valueOf(keysize, 2))
    930 				)
    931 			),
    932 			new ASN1(0xA1,
    933 				new ASN1(ASN1.SEQUENCE,
    934 					new ASN1(ASN1.SEQUENCE,
    935 						new ASN1(ASN1.OCTET_STRING, new ByteString("", HEX))
    936 					)
    937 				)
    938 			)
    939
    940 		);
    941 //	GPSystem.log(GPSystem.DEBUG, module.id, skd);
    942 	return skd;
    943 }
    944
    945
    946
    947 /**
    948  * Create a PKCS#15 certificate description
    949  *
    950  * @param {ByteString} commonObjectFlags default value is '0640'
    951  * @param {String} label the key label
    952  * @param {Key} pubKey the public key
    953  * @param {ByteString} certFID the file identifier of the certificate
    954  * @type ASN1
    955  * @return the certificate description
    956  */
    957 SmartCardHSM.buildCertDescription = function(label, commonObjectFlags, pubKey, certFID) {
    958 	if (!commonObjectFlags) {
    959 		commonObjectFlags = new ByteString("0x0640", HEX);
    960 	}
    961
    962 	// generate subject key id
    963 	var qx = pubKey.getComponent(Key.ECC_QX)
    964 	if (qx) {
    965 	  var enc = qx;
    966 	} else {
    967 	  var enc = pubKey.getComponent(Key.MODULUS);
    968 	}
    969 	var crypto = new Crypto();
    970 	var subjectKeyID = crypto.digest(Crypto.SHA_1, enc);
    971
    972 	var desc = 	new ASN1(ASN1.SEQUENCE,
    973 				new ASN1(ASN1.SEQUENCE,			// common object attributes
    974 					new ASN1(ASN1.UTF8String, new ByteString(label, UTF8)),
    975 					new ASN1(ASN1.BIT_STRING, commonObjectFlags)
    976 				),
    977 				new ASN1(ASN1.SEQUENCE,			// common certificate attributes
    978 					  new ASN1(ASN1.OCTET_STRING, subjectKeyID)
    979 				),
    980 				new ASN1(0xA1,					// type attributes
    981 					new ASN1(ASN1.SEQUENCE,			// x.509 certificate attributes
    982 						new ASN1(ASN1.SEQUENCE,			// path
    983 							new ASN1(ASN1.OCTET_STRING, certFID)
    984 						)
    985 					)
    986 				)
    987 			);
    988 	return desc;
    989 }
    990
    991
    992
    993 /**
    994  * Create a PKCS#15 data object description
    995  *
    996  * @param {String} label the key label
    997  * @param {ByteString} commonObjectFlags default value is '0640'
    998  * @param {ByteString} fid the file identifier of the data object
    999  * @param {String} applicationName the application name (Default "SmartCard-HSM")
    1000  * @type ASN1
    1001  * @return the Data Object Description
    1002  */
    1003 SmartCardHSM.buildDataObjectDescription = function(label, commonObjectFlags, fid, applicationName) {
    1004 	var privateDO = fid.byteAt(0) == SmartCardHSM.CONFIDENTIALDATAPREFIX;
    1005
    1006 	if (applicationName == undefined) {
    1007 		applicationName = "SmartCard-HSM";
    1008 	}
    1009 	if (!commonObjectFlags) {
    1010 		if (privateDO) {
    1011 			commonObjectFlags = new ByteString("0x06C0", HEX);
    1012 		} else {
    1013 			commonObjectFlags = new ByteString("0x0640", HEX);
    1014 		}
    1015 	}
    1016
    1017 	var desc = 	new ASN1(ASN1.SEQUENCE,
    1018 				new ASN1(ASN1.SEQUENCE,			// common object attributes
    1019 					new ASN1(ASN1.UTF8String, new ByteString(label, UTF8)),
    1020 					new ASN1(ASN1.BIT_STRING, commonObjectFlags)
    1021 				),
    1022 				new ASN1(ASN1.SEQUENCE,			// common data object attributes
    1023 					  new ASN1(ASN1.UTF8String, new ByteString(applicationName, UTF8))
    1024 				),
    1025 				new ASN1(0xA1,					// type attributes
    1026 					new ASN1(ASN1.SEQUENCE,			// path
    1027 						new ASN1(ASN1.OCTET_STRING, fid)
    1028 					)
    1029 				)
    1030 			);
    1031
    1032 	if (privateDO) {
    1033 		desc.get(0).add(new ASN1(ASN1.OCTET_STRING, ByteString.valueOf(1)));
    1034 	}
    1035 	return desc;
    1036 }
    1037
    1038
    1039
    1040 /**
    1041  * Create a PKCS#15 like KeyDomain description
    1042  *
    1043  * @param {String} label the key domain label
    1044  * @type ASN1
    1045  * @return the KeyDomain description
    1046  */
    1047 SmartCardHSM.buildKeyDomainDescription = function(label) {
    1048 	var kdd = 	new ASN1(ASN1.SEQUENCE,
    1049 					new ASN1(ASN1.SEQUENCE,
    1050 						new ASN1(ASN1.UTF8String, new ByteString(label, UTF8))
    1051 					)
    1052 				);
    1053
    1054 	return kdd;
    1055 }
    1056
    1057
    1058
    1059 /**
    1060  * Dump C-Data of Generate Asymmetric Key Pair command
    1061  *
    1062  * @param {ByteString} keydata the content of C-Data
    1063  */
    1064 SmartCardHSM.dumpKeyData = function(keydata) {
    1065 	GPSystem.log(GPSystem.DEBUG, module.id, keydata);
    1066 	var a = new ASN1(0x30, keydata);
    1067 	var a = new ASN1(a.getBytes());
    1068 	for (var i = 0; i < a.elements; i++) {
    1069 		GPSystem.log(GPSystem.DEBUG, module.id, a.get(i));
    1070 	}
    1071 }
    1072
    1073
    1074
    1075 /**
    1076  * Generate an asymmetric key pair
    1077  *
    1078  * @param {Number} newkid key identifier for new key
    1079  * @param {Number} signkid key identifier for signing the new public key
    1080  * @param {ByteString} keydata the key data template
    1081  * @type ByteString
    1082  * @return the certificate signing request containing the new public key
    1083  */
    1084 SmartCardHSM.prototype.generateAsymmetricKeyPair = function(newkid, signkid, keydata) {
    1085
    1086 	if (!this.limitedAPDUTransport) { // Use extended length
    1087 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x46, newkid, signkid, keydata, 65536, [0x9000]);
    1088 	} else {
    1089 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x46, newkid, signkid, keydata, [0x9000]);
    1090 		var rsp = this.readBinary(ByteString.valueOf(0xCE00 + newkid), 0);
    1091 	}
    1092
    1093 	return rsp;
    1094 }
    1095
    1096
    1097
    1098 /**
    1099  * Generate a symmetric key
    1100  *
    1101  * @param {Number} newkid key identifier for new key
    1102  * @param {Number} algo key generation algorithm
    1103  * @param {ByteString} keydata the key data template
    1104  * @type ByteString
    1105  * @return
    1106  */
    1107 SmartCardHSM.prototype.generateSymmetricKey = function(newkid, algo, keydata) {
    1108
    1109 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x48, newkid, algo, keydata, 0, [0x9000]);
    1110 	return rsp;
    1111 }
    1112
    1113
    1114
    1115 /**
    1116  * Return true is SmartCard-HSM is initialized
    1117  *
    1118  * @type Boolean
    1119  * @return true if initialized
    1120  */
    1121 SmartCardHSM.prototype.isInitialized = function() {
    1122 	var sw = this.queryUserPINStatus();
    1123 	if ((sw == 0x6984) || (sw == 0x6A88)) {		// V1.2: Not initialized / V2.0: Transport PIN
    1124 		var sw = this.queryInitializationCodeStatus();
    1125 		if (sw == 0x6A88) {
    1126 			return false;
    1127 		}
    1128 	}
    1129 	return true;
    1130 }
    1131
    1132
    1133
    1134 /**
    1135  * Initialize device and clear all keys and files
    1136  *
    1137  * @param {ByteString} options two byte option mask
    1138  * @param {ByteString} initialPIN initial user PIN value
    1139  * @param {ByteString} initializationCode secret code for device initialization (set during first use)
    1140  * @param {Number} retryCounterInitial retry counter for user PIN
    1141  * @param {Number} keyshares number of device key encryption key shares (optional)
    1142  */
    1143 SmartCardHSM.prototype.initDevice = function(options, initialPIN, initializationCode, retryCounterInitial, keyshares) {
    1144 	var s = new ASN1(0x30,
    1145 				new ASN1(0x80, options),
    1146 				new ASN1(0x81, initialPIN),
    1147 				new ASN1(0x82, initializationCode),
    1148 				new ASN1(0x91, ByteString.valueOf(retryCounterInitial))
    1149 				);
    1150
    1151 	if (typeof(keyshares) != "undefined") {
    1152 		s.add(new ASN1(0x92, ByteString.valueOf(keyshares)));
    1153 	}
    1154 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]);
    1155 }
    1156
    1157
    1158
    1159 /**
    1160  * Determine free memory
    1161  *
    1162  * @type Number
    1163  * @return the number of available bytes (this values is capped to 32767 on JCOP 2.4.1)
    1164  */
    1165 SmartCardHSM.prototype.getFreeMemory = function() {
    1166 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, 0, [0x9000, 0x6700]);
    1167
    1168 	if (this.card.SW != 0x9000) {
    1169 		return -1;
    1170 	}
    1171
    1172 	this.options = rsp.bytes(0, 2).toUnsigned();
    1173 	this.major = rsp.byteAt(rsp.length - 2);
    1174 	this.minor = rsp.byteAt(rsp.length - 1);
    1175 	this.platform = rsp.byteAt(rsp.length - 3);
    1176 	return rsp.bytes(rsp.length - 7, 4).toUnsigned();
    1177 }
    1178
    1179
    1180
    1181 /**
    1182  * Check if the RESET RETRY COUNTER command is enabled
    1183  *
    1184  * @type Boolean
    1185  * @return true if enable during initialization
    1186  */
    1187 SmartCardHSM.prototype.isResetRetryCounterEnabled = function() {
    1188 	if (typeof(this.options) == "undefined") {
    1189 		this.getFreeMemory();
    1190 	}
    1191 	return (this.options & 1) == 1;
    1192 }
    1193
    1194
    1195
    1196 /**
    1197  * Check if the RESET RETRY COUNTER command can reset the PIN
    1198  *
    1199  * @type Boolean
    1200  * @return true if enable during initialization
    1201  */
    1202 SmartCardHSM.prototype.isPINResetEnabled = function() {
    1203 	if (typeof(this.options) == "undefined") {
    1204 		this.getFreeMemory();
    1205 	}
    1206 	return (this.options & 0x20) == 0;
    1207 }
    1208
    1209
    1210
    1211 /**
    1212  * Parse the key domain status returned from the device
    1213  *
    1214  * @param {ByteString} status the R-DATA from the MANAGE KEY DOMAIN command
    1215  * @type object
    1216  * @return the decoded status Info
    1217  */
    1218 SmartCardHSM.prototype.parseKeyDomainStatus = function(status) {
    1219 	if (status.length == 0) {
    1220 		return { sw: this.card.SW };
    1221 	}
    1222
    1223 	var statusObject = {
    1224 		sw: this.card.SW,
    1225 		shares: status.byteAt(0),
    1226 		outstanding: status.byteAt(1),
    1227 		kcv: status.bytes(2, 8)
    1228 	}
    1229
    1230 	if (status.length > 10) {
    1231 		statusObject.keyDomain = status.bytes(10);
    1232 	}
    1233
    1234 	return statusObject;
    1235 }
    1236
    1237
    1238
    1239 /*
    1240  * Create DKEK Key Domain
    1241  *
    1242  * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command
    1243  * @param {Number} shares the number of DKEK shares to import
    1244  * @type Object
    1245  * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString}
    1246  */
    1247 SmartCardHSM.prototype.createDKEKKeyDomain = function(keyDomain, shares, label) {
    1248 	if (typeof(keyDomain) != "number") {
    1249 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number");
    1250 	}
    1251 	if (typeof(shares) != "number") {
    1252 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "shares must be a number");
    1253 	}
    1254
    1255 	if (label && typeof(label) != "string") {
    1256 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "label must be a string");
    1257 	}
    1258
    1259 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x01, keyDomain, ByteString.valueOf(shares), 0, [0x9000]);
    1260
    1261 	var status = this.parseKeyDomainStatus(rsp);
    1262
    1263 	if (label) {
    1264 		status.label = label;
    1265 		var fid = ByteString.valueOf((SmartCardHSM.KDDPREFIX << 8) + keyDomain);
    1266 		if (this.hasFile(fid)) {
    1267 			this.deleteFile(fid);
    1268 		}
    1269
    1270 		var kdd = SmartCardHSM.buildKeyDomainDescription(status.label);
    1271 		this.updateBinary(fid, 0, kdd.getBytes());
    1272 	}
    1273
    1274 	return status;
    1275 }
    1276
    1277
    1278
    1279 /**
    1280  * Create XKEK Key Domain
    1281  *
    1282  * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command
    1283  * @param {ByteString} keyDomainMembership either a 64 byte signature (old format) or a encoded TLV object with tag 54 or 55
    1284  * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString}
    1285  * @type Object
    1286  */
    1287 SmartCardHSM.prototype.createXKEKKeyDomain = function(keyDomain, groupSignerPublicKey, keyDomainMembership) {
    1288 	if (typeof(keyDomain) != "number") {
    1289 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number");
    1290 	}
    1291 	if ((keyDomain < 0) || (keyDomain > 0xFF)) {
    1292 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be between 0 and 255");
    1293 	}
    1294 	if (!(groupSignerPublicKey instanceof CVC)) {
    1295 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "groupSignerPublicKey must be a CVC instance");
    1296 	}
    1297 	if (!(keyDomainMembership instanceof ByteString)) {
    1298 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainMembership must be a ByteString");
    1299 	}
    1300
    1301 	var car = groupSignerPublicKey.getOuterCAR().getBytes();
    1302 	var chr = groupSignerPublicKey.getCHR();
    1303
    1304 	var pukrefdo = new ASN1(0x83, car);
    1305 	var pukref = pukrefdo.getBytes();
    1306
    1307 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
    1308
    1309 	if (keyDomainMembership.length == 64) {
    1310 		keyDomainMembership = new ASN1(0x53, keyDomainMembership).getBytes();
    1311 	}
    1312 	var cdata = groupSignerPublicKey.getASN1().value.concat(keyDomainMembership);
    1313
    1314 	if (cdata.length <= this.maxCData) {
    1315 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x02, keyDomain, cdata, 0, [0x9000]);
    1316 	} else {
    1317 		this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata);
    1318 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x02, keyDomain, 0, [0x9000]);
    1319 	}
    1320
    1321 	var status = this.parseKeyDomainStatus(rsp);
    1322
    1323 	status.label = chr.toString();
    1324
    1325 	var fid = ByteString.valueOf((SmartCardHSM.KDDPREFIX << 8) + keyDomain);
    1326 	if (this.hasFile(fid)) {
    1327 		this.deleteFile(fid);
    1328 	}
    1329
    1330 	var kdd = SmartCardHSM.buildKeyDomainDescription(status.label);
    1331 	this.updateBinary(fid, 0, kdd.getBytes());
    1332
    1333 	return status;
    1334 }
    1335
    1336
    1337
    1338 /**
    1339  * Associate XKEK Key Domain
    1340  *
    1341  * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command
    1342  * @param {ByteString} keyDomainUID a encoded TLV object with tag 51 containing the key domain uid of the associated domain
    1343  * @param {ByteString} keyDomainAssociation a encoded TLV object with tag 56 or 57
    1344  * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString}
    1345  * @type Object
    1346  */
    1347 SmartCardHSM.prototype.associateXKEKKeyDomain = function(keyDomain, groupSignerPublicKey, keyDomainUID, keyDomainAssociation) {
    1348 	if (typeof(keyDomain) != "number") {
    1349 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be a number");
    1350 	}
    1351 	if ((keyDomain < 0) || (keyDomain > 0xFF)) {
    1352 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomain must be between 0 and 255");
    1353 	}
    1354 	if (!(groupSignerPublicKey instanceof CVC)) {
    1355 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "groupSignerPublicKey must be a ByteString");
    1356 	}
    1357 	if (!(keyDomainUID instanceof ByteString)) {
    1358 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainUID must be a ByteString");
    1359 	}
    1360 	if (!(keyDomainAssociation instanceof ByteString)) {
    1361 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyDomainAssociation must be a ByteString");
    1362 	}
    1363
    1364 	var car = groupSignerPublicKey.getOuterCAR().getBytes();
    1365
    1366 	var pukrefdo = new ASN1(0x83, car);
    1367 	var pukref = pukrefdo.getBytes();
    1368
    1369 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
    1370
    1371 	var cdata = groupSignerPublicKey.getASN1().value.concat(keyDomainUID).concat(keyDomainAssociation);
    1372
    1373 	if (cdata.length <= this.maxCData) {
    1374 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x05, keyDomain, cdata, 0);
    1375 	} else {
    1376 		this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata);
    1377 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x05, keyDomain, 0);
    1378 	}
    1379
    1380 	return this.parseKeyDomainStatus(status);
    1381 }
    1382
    1383
    1384
    1385 /**
    1386  * Derive XKEK
    1387  *
    1388  * @param {Number} keyDomain number of key domain in the range 0 to the maximum defined in the INITIALIZE DEVICE command
    1389  * @param {ByteString} derivationParam
    1390  * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and the key domain UID{ByteString}
    1391  * @type Object
    1392  */
    1393 SmartCardHSM.prototype.deriveXKEK = function(keyid, peerPublicKey, derivationParam) {
    1394 	if (typeof(keyid) != "number") {
    1395 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyid must be a number");
    1396 	}
    1397 	if ((keyid < 1) || (keyid > 0xFF)) {
    1398 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "keyid must be between 1 and 255");
    1399 	}
    1400 	if (!(peerPublicKey instanceof CVC)) {
    1401 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "peerPublicKey must be a CVC");
    1402 	}
    1403 	if (!(derivationParam instanceof ByteString)) {
    1404 		throw new GPError("SmartCardHSM", GPError.INVALID_DATA, 1, "derivationParam must be a ByteString");
    1405 	}
    1406
    1407 	var car = peerPublicKey.getOuterCAR().getBytes();
    1408
    1409 	var pukrefdo = new ASN1(0x83, car);
    1410 	var pukref = pukrefdo.getBytes();
    1411
    1412 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
    1413
    1414 	var kdp = new ASN1(0x50, derivationParam).getBytes();
    1415 	var cdata = peerPublicKey.getASN1().value.concat(kdp);
    1416
    1417 	if (cdata.length <= this.maxCData) {
    1418 		// Le is usually not required, but versions 3.1 to 3.3 fail without Le (#178)
    1419 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, 0x84, cdata, 0, [0x9000]);
    1420 	} else {
    1421 		this.updateBinary(ByteString.valueOf(0x2F10), 0, cdata);
    1422 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, 0x84, [0x9000]);
    1423 	}
    1424 }
    1425
    1426
    1427
    1428 /**
    1429  * Query the status of the key domain
    1430  *
    1431  * @param {Number} keyDomain the number of the key domain which will be queried, default is 0
    1432  * @type Object
    1433  * @return object with properties sw{Number}, shares{Number}, outstanding{Number}, kcv{ByteString} and for a XKEK key domain the key domain UID{ByteString}
    1434  */
    1435 SmartCardHSM.prototype.queryKeyDomainStatus = function(keyDomain) {
    1436 	if (!keyDomain) {
    1437 		keyDomain = 0;
    1438 	}
    1439
    1440 	var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, 0);
    1441
    1442 	return this.parseKeyDomainStatus(status);
    1443 }
    1444
    1445
    1446
    1447 /**
    1448  * Delete the key encryption key in a key domain
    1449  *
    1450  * @param {Number} keyDomain the number of the key domain
    1451  */
    1452 SmartCardHSM.prototype.deleteKEK = function(keyDomain) {
    1453 	var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x04, keyDomain, [0x9000]);
    1454
    1455 	return this.parseKeyDomainStatus(status);
    1456 }
    1457
    1458
    1459
    1460 /**
    1461  * Delete the empty key domain
    1462  *
    1463  * @param {Number} keyDomain the number of the key domain
    1464  */
    1465 SmartCardHSM.prototype.deleteKeyDomain = function(keyDomain) {
    1466 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x03, keyDomain, [0x9000]);
    1467
    1468 	var fid = ByteString.valueOf((SmartCardHSM.KDDPREFIX << 8) + keyDomain);
    1469 	if (this.hasFile(fid)) {
    1470 		this.deleteFile(fid);
    1471 	}
    1472 }
    1473
    1474
    1475
    1476 /**
    1477  * Return the label associated with the key domain or undefined.
    1478  *
    1479  * @param {Number} keyDomain the number of the key domain
    1480  */
    1481 SmartCardHSM.prototype.getKeyDomainLabel = function(keyDomain) {
    1482 	var fid = ByteString.valueOf((SmartCardHSM.KDDPREFIX << 8) + keyDomain);
    1483 	try	{
    1484 		var bin = this.readBinary(fid);
    1485 		if (bin.byteAt(0) != 0x30) {
    1486 			return;
    1487 		}
    1488 		var a = new ASN1(bin);
    1489 		return a.get(0).get(0).value.toString(UTF8);
    1490 	} catch(e) {
    1491 		// Return undefined if no description is set
    1492 		return;
    1493 	}
    1494 }
    1495
    1496
    1497
    1498 /**
    1499  * Import DKEK share or query status
    1500  *
    1501  * @param {Number} keyDomain the number of the key domain
    1502  * @param {ByteString} keyshare 32 byte key share
    1503  * @type Object
    1504  * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString}
    1505  */
    1506 SmartCardHSM.prototype.importKeyShare = function(keyDomain, keyshare) {
    1507 	if (typeof(keyDomain) != "number") {
    1508 		keyshare = keyDomain;
    1509 		keyDomain = 0;
    1510 	}
    1511 	if (typeof(keyshare) != "undefined") {
    1512 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, keyshare, 0, [0x9000]);
    1513 	} else {
    1514 		var status = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x52, 0x00, keyDomain, 0);
    1515 	}
    1516 	if (status.length == 0) {
    1517 		return { sw: this.card.SW };
    1518 	}
    1519
    1520 	var statusObject = {
    1521 		sw: this.card.SW,
    1522 		shares: status.byteAt(0),
    1523 		outstanding: status.byteAt(1),
    1524 		kcv: status.bytes(2, 8)
    1525 	}
    1526
    1527 	if (status.length > 10) {
    1528 		statusObject.keyDomain = status.bytes(10);
    1529 	}
    1530
    1531 	return statusObject;
    1532 }
    1533
    1534
    1535
    1536 /**
    1537  * Decrypt and import a DKEK share
    1538  *
    1539  * @param {ByteString} keyshare the encrypted key share as read from the .pbe file
    1540  * @param {ByteString} password the password
    1541  * @param {Number} keyDomain the number of the key domain
    1542  * @return object with properties sw{Number}, shares{Number}, outstanding{Number} and kcv{ByteString}
    1543  */
    1544 SmartCardHSM.prototype.importEncryptedKeyShare = function(keyshare, password, keyDomain) {
    1545 	if (typeof(keyDomain) == "undefined") {
    1546 		keyDomain = 0;
    1547 	}
    1548
    1549 	var dkek = DKEK.decryptKeyShare(keyshare, password);
    1550 //	print("Importing into SmartCard-HSM");
    1551 	var r = this.importKeyShare(keyDomain, dkek);
    1552 	dkek.clear();
    1553 	return r;
    1554 }
    1555
    1556
    1557
    1558 /**
    1559  * Wrap key under DKEK
    1560  *
    1561  * @param {Number} id key id
    1562  * @type ByteString
    1563  * @return key blob with encrypted key value
    1564  */
    1565 SmartCardHSM.prototype.wrapKey = function(id) {
    1566 	var keyblob = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x72, id, 0x92, 65536, [0x9000]);
    1567 	return keyblob;
    1568 }
    1569
    1570
    1571
    1572 /**
    1573  * Unwrap key with DKEK
    1574  *
    1575  * @param {Number} id key id
    1576  * @param {ByteString} keyblob the wrapped key
    1577  */
    1578 SmartCardHSM.prototype.unwrapKey = function(id, keyblob) {
    1579 	if (keyblob.length < this.maxCData) {
    1580 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, keyblob, [0x9000]);
    1581 	} else {
    1582 		this.updateBinary(ByteString.valueOf(0x2F10), 0, keyblob);
    1583 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x93, [0x9000]);
    1584 	}
    1585 }
    1586
    1587
    1588
    1589 /**
    1590  * Replace symmetric key value encrypted under current key
    1591  *
    1592  * @param {Number} id key id
    1593  * @param {ByteString} keyblob the wrapped key
    1594  */
    1595 SmartCardHSM.prototype.unwrapAndReplaceKey = function(id, keyblob) {
    1596 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x74, id, 0x94, keyblob, [0x9000]);
    1597 }
    1598
    1599
    1600
    1601 /**
    1602  * Derive Symmetric Key
    1603  *
    1604  * @param {Number} id key id
    1605  * @param {Number} algo algorithm id (one of ALG_CBC_ENC, ALG_CBC_DEC, ALG_CMAC or ALG_DERIVE_SP800_56C)
    1606  * @param {ByteString} derivationParam the derivation parameter
    1607  * @type ByteString
    1608  * @return derived key value
    1609  */
    1610 SmartCardHSM.prototype.deriveSymmetricKey = function(id, algo, derivationParam) {
    1611 	var derivedKeyValue = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x78, id, algo, derivationParam, 0, [0x9000]);
    1612 	return derivedKeyValue;
    1613 }
    1614
    1615
    1616
    1617 /**
    1618  * Verify User PIN
    1619  *
    1620  * @param {ByteString} userPIN user PIN value
    1621  * @return the status word SW1/SW2 returned by the device
    1622  */
    1623 SmartCardHSM.prototype.verifyUserPIN = function(userPIN) {
    1624 	if (userPIN) {
    1625 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, 0x81, userPIN);
    1626 		return this.card.SW;
    1627 	} else {
    1628 		var cs = this.getNativeCardService();
    1629 		cs.verifyPassword();
    1630 		return this.queryUserPINStatus();
    1631 	}
    1632 }
    1633
    1634
    1635
    1636 /**
    1637  * Logout
    1638  *
    1639  */
    1640 SmartCardHSM.prototype.logout = function() {
    1641 	this.card.clearCredential();
    1642 	var fcp = this.card.sendApdu(0x00, 0xA4, 0x04, 0x04, new ByteString("E82B0601040181C31F0201", HEX), 0, [0x9000]);
    1643 	var a = new ASN1(fcp);
    1644 	var v = a.find(0x85).value;
    1645 	this.options = v.bytes(0, 2).toUnsigned();
    1646 	this.major = v.byteAt(v.length - 2);
    1647 	this.minor = v.byteAt(v.length - 1);
    1648 	if (v.length >= 5) {
    1649 		this.platform = v.byteAt(v.length - 3);
    1650 	}
    1651 }
    1652
    1653
    1654
    1655 /**
    1656  * Change User PIN
    1657  *
    1658  * @param {ByteString} currentPIN current user PIN value
    1659  * @param {ByteString} newPIN new user PIN value
    1660  */
    1661 SmartCardHSM.prototype.changeUserPIN = function(currentPIN, newPIN) {
    1662 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x81, currentPIN.concat(newPIN), [0x9000]);
    1663 }
    1664
    1665
    1666
    1667 /**
    1668  * Unblock and set User PIN
    1669  *
    1670  * @param {ByteString} initializationCode the initialization code
    1671  * @param {ByteString} newPIN new user PIN value (optional)
    1672  */
    1673 SmartCardHSM.prototype.unblockUserPIN = function(initializationCode, newPIN) {
    1674 	if (newPIN) {
    1675 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2C, 0x00, 0x81, initializationCode.concat(newPIN), [0x9000]);
    1676 	} else {
    1677 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2C, 0x01, 0x81, initializationCode, [0x9000]);
    1678 	}
    1679 }
    1680
    1681
    1682
    1683 /**
    1684  * Change InitializationCode
    1685  *
    1686  * @param {ByteString} initializationCode current initialization code
    1687  * @param {ByteString} newInitializationCode new initialization code
    1688  */
    1689 SmartCardHSM.prototype.changeInitializationCode = function(initializationCode, newInitializationCode) {
    1690 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x24, 0x00, 0x88, initializationCode.concat(newInitializationCode), [0x9000]);
    1691 }
    1692
    1693
    1694
    1695 SmartCardHSM.describePINStatus = function(sw, name) {
    1696 	var str;
    1697 	switch(sw) {
    1698 	case 0x9000:
    1699 		str = name + " authenticated";
    1700 		break;
    1701 	case 0x6984:
    1702 		str = name + " in transport mode or device not initialized";
    1703 		break;
    1704 	case 0x6A88:
    1705 		str = name + " not initialized";
    1706 		break;
    1707 	case 0x6983:
    1708 		str = name + " blocked";
    1709 		break;
    1710 	case 0x6300:
    1711 		str = name + " not authenticated";
    1712 		break;
    1713 	default:
    1714 		str = name + " not verified, " + (sw & 0xF) + " tries remaining";
    1715 		break;
    1716 	}
    1717 	return str + " (" + ByteString.valueOf(sw).toString(HEX) + ")";
    1718 }
    1719
    1720
    1721
    1722 /**
    1723  * Request PIN Status Information
    1724  *
    1725  * @param {Number} p2 the PIN object id
    1726  * @type Number
    1727  * @return the status word SW1/SW2 returned by the device
    1728  */
    1729 SmartCardHSM.prototype.queryPINStatus = function(p2) {
    1730 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x20, 0x00, p2, 0);
    1731 	return this.card.SW;
    1732 }
    1733
    1734
    1735
    1736 /**
    1737  * Request PIN Status Information
    1738  *
    1739  * @type Number
    1740  * @return the status word SW1/SW2 returned by the device
    1741  */
    1742 SmartCardHSM.prototype.queryUserPINStatus = function() {
    1743 	return this.queryPINStatus(0x81);
    1744 }
    1745
    1746
    1747
    1748 /**
    1749  * Request Initialization Code Status
    1750  *
    1751  * @type Number
    1752  * @return the status word SW1/SW2 returned by the device
    1753  */
    1754 SmartCardHSM.prototype.queryInitializationCodeStatus = function() {
    1755 	return this.queryPINStatus(0x88);
    1756 }
    1757
    1758
    1759
    1760 /**
    1761  * Enumerate Objects
    1762  *
    1763  * @return the enumeration
    1764  */
    1765 SmartCardHSM.prototype.enumerateObjects = function() {
    1766 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x58, 0x00, 0x00, 65536, [0x9000]);
    1767 	return rsp;
    1768 }
    1769
    1770
    1771
    1772 /**
    1773  * Generate random data
    1774  *
    1775  * @param {Number} length number of bytes
    1776  * @return the random bytes
    1777  */
    1778 SmartCardHSM.prototype.generateRandom = function(length) {
    1779 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x84, 0x00, 0x00, length, [0x9000]);
    1780 	return rsp;
    1781 }
    1782
    1783
    1784
    1785 /**
    1786  * Sign data using referenced key
    1787  *
    1788  * @param {Number} keyid the key identifier for signing
    1789  * @param {algo} algo the algorithm identifier
    1790  * @param {ByteString} data the data to be signed
    1791  * @return the signature value
    1792  */
    1793 SmartCardHSM.prototype.sign = function(keyid, algo, data) {
    1794 	if (data.length <= this.maxCData) {
    1795 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, data, 0x10000, [0x9000]);
    1796 	} else {
    1797 		this.updateBinary(ByteString.valueOf(0x2F10), 0, data);
    1798 		var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x68, keyid, algo, 0x10000, [0x9000]);
    1799 	}
    1800
    1801 	return rsp;
    1802 }
    1803
    1804
    1805
    1806 /**
    1807  * Decipher cryptogram or agree shared secret using Diffie-Hellman
    1808  *
    1809  * @param {Number} keyid the key identifier
    1810  * @param {Number} algo the algorithm identifier
    1811  * @param {ByteString} data the the cryptogram or concatenation of x || y of ECC public key
    1812  * @return the plain output
    1813  */
    1814 SmartCardHSM.prototype.decipher = function(keyid, algo, data) {
    1815 	var rsp = this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x62, keyid, algo, data, 0x00, [0x9000]);
    1816 	return rsp;
    1817 }
    1818
    1819
    1820
    1821 /**
    1822  * Verify card verifiable certificate
    1823  *
    1824  * @param {CVC} cvc the card verifiable certificate
    1825  **/
    1826 SmartCardHSM.prototype.verifyCertificate = function(cvc) {
    1827
    1828 	// Check if public key is already known
    1829 	var chr = cvc.getCHR().getBytes();
    1830
    1831 	var pukrefdo = new ASN1(0x83, chr);
    1832 	var pukref = pukrefdo.getBytes();
    1833
    1834 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000, 0x6A88]);
    1835
    1836 	if (this.card.SW == 0x9000) {
    1837 		return;
    1838 	}
    1839
    1840 	// Select public key for verification
    1841 	var car = cvc.getCAR().getBytes();
    1842
    1843 	var pukrefdo = new ASN1(0x83, car);
    1844 	var pukref = pukrefdo.getBytes();
    1845
    1846 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x22, 0x81, 0xB6, pukref, [0x9000]);
    1847
    1848 	// Extract value of 7F21
    1849 	var tl = new TLVList(cvc.getBytes(), TLV.EMV);
    1850 	var t = tl.index(0);
    1851 	var v = t.getValue();
    1852
    1853 	this.card.sendSecMsgApdu(Card.ALL, 0x00, 0x2A, 0x00, 0xBE, v, [0x9000]);
    1854 }
    1855
    1856
    1857
    1858 /**
    1859  * Enumerate CA certificates
    1860  *
    1861  * @type String[]
    1862  * @return the list of certificate labels
    1863  */
    1864 SmartCardHSM.prototype.enumerateCACertificates = function() {
    1865 	this.canamemap = [];
    1866 	this.caidmap = []
    1867 	this.caids = [];
    1868 	var certlist = [];
    1869
    1870 	var fobs = this.enumerateObjects();
    1871
    1872 	// Process PKCS#15 certificate descriptions
    1873 	for (var i = 0; i < fobs.length; i+= 2) {
    1874 		if (fobs.byteAt(i) == SmartCardHSM.CERTDPREFIX) {
    1875 			var id = fobs.byteAt(i + 1);
    1876 			this.caids.push(id);
    1877 			var fid = ByteString.valueOf((SmartCardHSM.CACERTIFICATEPREFIX << 8) + id);
    1878 			var descbin = this.readBinary(fobs.bytes(i, 2));
    1879 			var asn = new ASN1(descbin);
    1880 			var coa = asn.get(0);
    1881 			if (coa.elements > 0) {
    1882 				var label = coa.get(0).value.toString(ASCII);
    1883 			} else {
    1884 				var label = "No label (" + i + ")";
    1885 			}
    1886 			var cert = this.readBinary(fid);
    1887 			certlist.push(label);
    1888 			this.canamemap[label] = cert;
    1889 			cert.id = id;
    1890 			this.caidmap[label] = id;
    1891 		}
    1892 	}
    1893
    1894 	return certlist;
    1895 }
    1896
    1897
    1898
    1899 /**
    1900  * Return CA certificate with label
    1901  *
    1902  * @param {String} label the certificate label
    1903  * @type ByteString
    1904  * @return the encoded certificate
    1905  */
    1906 SmartCardHSM.prototype.getCACertificate = function(label) {
    1907 	if (typeof(this.caids) == "undefined") {
    1908 		this.enumerateCACertificates();
    1909 	}
    1910
    1911 	return this.canamemap[label];
    1912 }
    1913
    1914
    1915
    1916 /**
    1917  * Determine an unused CA certificate identifier
    1918  *
    1919  * @type Number
    1920  * @return a free CA certificate identifier or -1 if all identifier in use
    1921  */
    1922 SmartCardHSM.prototype.determineFreeCAId = function() {
    1923 	var fobs = this.enumerateObjects();
    1924
    1925 	return SmartCardHSM.determineFreeId(SmartCardHSM.CACERTIFICATEPREFIX, fobs);
    1926 }
    1927
    1928
    1929
    1930 /**
    1931  * Add a new CA certificate to the map
    1932  *
    1933  * @param {X509} cert the CA certificate
    1934  * @param {Number} id the corresponding id
    1935  * @param {String} label the corresponding label
    1936  */
    1937 SmartCardHSM.prototype.addCACertificateToMap = function(cert, id, label) {
    1938 	if (!this.caidmap[label]) {
    1939 		// new id
    1940 		this.caids.push(id);
    1941 		this.caidmap[label] = id;
    1942 	}
    1943 	this.canamemap[label] = cert;
    1944 }
    1945
    1946
    1947
    1948 /**
    1949  * Enumerate key objects in the SmartCard-HSM and build the map of keys
    1950  *
    1951  * @type String[]
    1952  * @return the list of key labels
    1953  */
    1954 SmartCardHSM.prototype.enumerateKeys = function() {
    1955 	this.namemap = [];
    1956 	this.idmap = [];
    1957 	this.idlist = [];
    1958 	this.p15idmap = [];
    1959
    1960 	var fobs = this.enumerateObjects();
    1961
    1962 	// Process keys
    1963 	for (var i = 0; i < fobs.length; i += 2) {
    1964 		if ((fobs.byteAt(i) == SmartCardHSM.KEYPREFIX) || (fobs.byteAt(i) == 0xFF)) {
    1965 			var kid = fobs.byteAt(i + 1);
    1966 			if (kid > 0) {
    1967 //				GPSystem.log(GPSystem.DEBUG, module.id, "Found key: " + kid);
    1968 				var key = new SmartCardHSMKey(this, kid);
    1969 				this.idmap[kid] = key;
    1970 				this.idlist.push(kid);
    1971 				this.updateKey(key);
    1972 			}
    1973 		}
    1974 	}
    1975
    1976 	var keylist = [];
    1977 	// Process PKCS#15 private key descriptions
    1978 	for (var i = 0; i < fobs.length; i += 2) {
    1979 		if (fobs.byteAt(i) == SmartCardHSM.PRKDPREFIX) {
    1980 			var kid = fobs.byteAt(i + 1);
    1981 			var descbin = this.readBinary(fobs.bytes(i, 2));
    1982 			if (descbin.length > 2) {
    1983 				try {
    1984 					var desc = new ASN1(descbin);
    1985 					if (desc.elements < 3) {
    1986 						continue;
    1987 					}
    1988 				}
    1989 				catch(e) {
    1990 					continue;
    1991 				}
    1992 				var key = this.idmap[kid];
    1993 				if (key) {
    1994 					key.setDescription(desc);
    1995 					var label = key.getLabel();
    1996 //					GPSystem.log(GPSystem.DEBUG, module.id, key.getId() + " - " + label);
    1997 					if (label) {
    1998 						keylist.push(label);
    1999 						this.namemap[label] = key;
    2000 					}
    2001 					var p15id = key.getPKCS15Id();
    2002 					this.p15idmap[p15id.toString(HEX)] = key;
    2003 				}
    2004 			}
    2005 		}
    2006 	}
    2007
    2008 	return keylist;
    2009 }
    2010
    2011
    2012
    2013 /**
    2014  * Get key ids
    2015  *
    2016  * @type Number[]
    2017  * @return a list of key identifier
    2018  */
    2019 SmartCardHSM.prototype.getKeyIds = function() {
    2020 	if (typeof(this.idlist) == "undefined") {
    2021 		this.enumerateKeys();
    2022 	}
    2023 	return this.idlist;
    2024 }
    2025
    2026
    2027
    2028 /**
    2029  * Determine an unused key identifier
    2030  *
    2031  * @type Number
    2032  * @return a free key identifier or -1 if all key identifier in use
    2033  */
    2034 SmartCardHSM.prototype.determineFreeKeyId = function() {
    2035 	if (typeof(this.idlist) == "undefined") {
    2036 		this.enumerateKeys();
    2037 	}
    2038 	for (var i = 1; i < 256; i++) {
    2039 		if (this.idmap[i] == undefined) {
    2040 			return i;
    2041 		}
    2042 	}
    2043 	throw new GPError("SmartCardHSM", GPError.OUT_OF_MEMORY, 1, "Key idx exhausted");
    2044 }
    2045
    2046
    2047
    2048 /**
    2049  * Update key attributes, in particular the use counter
    2050  *
    2051  * @param {HSMKey} key the HSM key
    2052  */
    2053 SmartCardHSM.prototype.updateKey = function(key) {
    2054 	var fid = ByteString.valueOf((SmartCardHSM.KEYPREFIX << 8) + key.getId());
    2055 	try	{
    2056 		var fcp = this.selectFile(fid);
    2057 	}
    2058 	catch(e) {
    2059 		return;
    2060 	}
    2061 	var a = new ASN1(fcp);
    2062 	var pi = a.find(0xA5);
    2063 	if (!pi) {
    2064 		return;
    2065 	}
    2066 	var kc = pi.find(0x90);
    2067 	if (kc) {
    2068 		var c = kc.value.toUnsigned();
    2069
    2070 		if (c != 0xFFFFFFFF) {
    2071 			key.useCounter = c;
    2072 		}
    2073 	}
    2074
    2075 	var kd = pi.find(0x91);
    2076 	if (kd) {
    2077 		key.algorithms = kd.value;
    2078 	}
    2079
    2080 	var kd = pi.find(0x92);
    2081 	if (kd) {
    2082 		key.keyDomain = kd.value.toUnsigned();
    2083 	}
    2084 }
    2085
    2086
    2087
    2088 /**
    2089  * Add a new key to the map of keys
    2090  *
    2091  * @param {HSMKey} key the HSM key
    2092  */
    2093 SmartCardHSM.prototype.addKeyToMap = function(key) {
    2094 	var id = key.getId();
    2095 	this.idmap[id] = key;
    2096
    2097 	var label = key.getLabel();
    2098 	if (label) {
    2099 		this.namemap[label] = key;
    2100 	}
    2101
    2102 	var p15id = key.getPKCS15Id();
    2103 	if (p15id) {
    2104 		this.p15idmap[p15id.toString(HEX)] = key;
    2105 	}
    2106 }
    2107
    2108
    2109
    2110 /**
    2111  * Get a key reference object
    2112  *
    2113  * @param {String/Number/ByteString} labelOrId label or id of key
    2114  * @returns the key or null if not found
    2115  * @type Key
    2116  */
    2117 SmartCardHSM.prototype.getKey = function(labelOrId) {
    2118 	if (typeof(this.idlist) == "undefined") {
    2119 		this.enumerateKeys();
    2120 	}
    2121
    2122 	if (typeof(labelOrId) == "number") {
    2123 		var key = this.idmap[labelOrId];
    2124 	} else if (typeof(labelOrId) == "string") {
    2125 		var key = this.namemap[labelOrId];
    2126 	} else {
    2127 		var key = this.p15idmap[labelOrId.toString(HEX)];
    2128 	}
    2129
    2130 	if (key == undefined) {
    2131 		return null;
    2132 	}
    2133 	return key;
    2134 }
    2135
    2136
    2137
    2138 /**
    2139  * Return a list of key objects
    2140  *
    2141  * @type SmartCardHSMKey[]
    2142  * @return the list of keys
    2143  */
    2144 SmartCardHSM.prototype.getKeys = function() {
    2145 	if (typeof(this.idlist) == "undefined") {
    2146 		this.enumerateKeys();
    2147 	}
    2148
    2149 	var keylist = [];
    2150 	for (var i in this.idmap) {
    2151 		keylist.push(this.idmap[i]);
    2152 	}
    2153 	return keylist;
    2154 }
    2155
    2156
    2157
    2158 /**
    2159  * Determine a free id in the list of FID for the given prefix.
    2160  *
    2161  * @param {Number} the prefix to look at
    2162  * @param {ByteString} the list of FID as returned from the device
    2163  * @type Number
    2164  * @return a free id for the given prefix or -1 if range is exhausted.
    2165  */
    2166 SmartCardHSM.determineFreeId = function(prefix, fobs) {
    2167 	var map = new Bitmap(256);
    2168
    2169 	for (var i = 0; i < fobs.length; i+= 2) {
    2170 		if (fobs.byteAt(i) == prefix) {
    2171 			map.toggle(fobs.byteAt(i + 1));
    2172 		}
    2173 	}
    2174
    2175 	return map.determineFirstUnset();
    2176 }
    2177
    2178
    2179
    2180 /**
    2181  * Determine a free FID in the list of FID for the given prefix.
    2182  *
    2183  * @param {Number} the prefix to look at
    2184  * @param {ByteString} the list of FID as returned from the device
    2185  * @type ByteString
    2186  * @return a free two byte file identifier (FID) for the given prefix or null if range is exhausted.
    2187  */
    2188 SmartCardHSM.determineFreeFid = function(prefix, fobs) {
    2189 	var id = SmartCardHSM.determineFreeId(prefix, fobs);
    2190 	if (id < 0) {
    2191 		return null;
    2192 	}
    2193 	return ByteString.valueOf((prefix << 8) + id);
    2194 }
    2195
    2196
    2197
    2198 /**
    2199  * Enumerate Data Objects
    2200  *
    2201  * @type String[]
    2202  * @return the list of data object labels
    2203  */
    2204 SmartCardHSM.prototype.enumerateDataObjects = function() {
    2205 	this.donamemap = [];
    2206 	var dolist = [];
    2207
    2208 	var fobs = this.enumerateObjects();
    2209
    2210 	// Process PKCS#15 data object descriptions
    2211 	for (var i = 0; i < fobs.length; i+= 2) {
    2212 		if (fobs.byteAt(i) == SmartCardHSM.DODPREFIX) {
    2213 			var descfid = fobs.bytes(i, 2);
    2214 			var descbin = this.readBinary(descfid);
    2215 			var asn = new ASN1(descbin);
    2216 //			print(asn);
    2217 			var coa = asn.get(0);
    2218 			if (coa.elements > 0) {
    2219 				var label = coa.get(0).value.toString(ASCII);
    2220 			} else {
    2221 				var label = "No label (" + i + ")";
    2222 			}
    2223 			var taga1 = asn.find(0xA1);
    2224 			if (taga1) {
    2225 				var datafid = taga1.get(0).get(0).value;
    2226 				this.donamemap[label] = { datafid: datafid, descfid: descfid };
    2227 				dolist.push(label);
    2228 			}
    2229 		}
    2230 	}
    2231
    2232 	return dolist;
    2233 }
    2234
    2235
    2236
    2237 /**
    2238  * Check if the data object is present
    2239  *
    2240  * @param {String} label the label
    2241  * @type boolean
    2242  * @return true if the data object exists
    2243  */
    2244 SmartCardHSM.prototype.hasDataObject = function(label) {
    2245 	if (typeof(this.donamemap) == "undefined"){
    2246 		this.enumerateDataObjects();
    2247 	}
    2248 	return (this.donamemap[label] != undefined);
    2249 }
    2250
    2251
    2252
    2253 /**
    2254  * Return the file identifier containing the data object.
    2255  *
    2256  * @param {String} label the label.
    2257  * @type ByteString
    2258  * @return the two byte file identifier
    2259  */
    2260 SmartCardHSM.prototype.getDataObjectFileIdentifier = function(label) {
    2261 	if (typeof(this.donamemap) == "undefined"){
    2262 		this.enumerateDataObjects();
    2263 	}
    2264 	var e = this.donamemap[label];
    2265 	if (e == undefined) {
    2266 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " not found");
    2267 	}
    2268 	return e.datafid;
    2269 }
    2270
    2271
    2272
    2273 /**
    2274  * Import a data object
    2275  *
    2276  * @param {String} label the unique label to reference the new data object
    2277  * @param {Boolean} privObj true to store the data object with read protection
    2278  * @param {ByteString} data the data blob to store
    2279  */
    2280 SmartCardHSM.prototype.importDataObject = function(label, privObj, data) {
    2281 	var fobs = this.enumerateObjects();
    2282
    2283 	var e = this.donamemap[label];
    2284 	if (e != undefined) {
    2285 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " does already exist");
    2286 	}
    2287
    2288 	if (privObj) {
    2289 		var datafid = SmartCardHSM.determineFreeFid(SmartCardHSM.CONFIDENTIALDATAPREFIX, fobs);
    2290 	} else {
    2291 		var datafid = SmartCardHSM.determineFreeFid(SmartCardHSM.PUBLICDATAPREFIX, fobs);
    2292 	}
    2293
    2294 	if (datafid == null) {
    2295 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Out of space for data objects");
    2296 	}
    2297
    2298 	var desc = SmartCardHSM.buildDataObjectDescription(label, undefined, datafid, "KeyManager");
    2299
    2300 	var descfid = SmartCardHSM.determineFreeFid(SmartCardHSM.DODPREFIX, fobs);
    2301
    2302 	if (descfid == null) {
    2303 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Out of space for data objects descriptor");
    2304 	}
    2305
    2306 	this.updateBinary(datafid, 0, data);
    2307 	this.updateBinary(descfid, 0, desc.getBytes());
    2308 	this.donamemap[label] = { datafid: datafid, descfid: descfid };
    2309 }
    2310
    2311
    2312
    2313 /**
    2314  * Delete the data object references by the label.
    2315  *
    2316  * @param {String} label the label of the data object
    2317  */
    2318 SmartCardHSM.prototype.deleteDataObject = function(label) {
    2319 	if (typeof(this.donamemap) == "undefined"){
    2320 		this.enumerateDataObjects();
    2321 	}
    2322 	var e = this.donamemap[label];
    2323 	if (e == undefined) {
    2324 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Data object " + label + " not found");
    2325 	}
    2326 	this.deleteFile(e.descfid);
    2327 	this.deleteFile(e.datafid);
    2328 	delete this.donamemap[label];
    2329 }
    2330
    2331
    2332
    2333 /**
    2334  * Get crypto object
    2335  *
    2336  * @type HSMCrypto
    2337  * @return the HSMCrypto object
    2338  */
    2339 SmartCardHSM.prototype.getCrypto = function() {
    2340 	if (this.crypto == undefined) {
    2341 		this.crypto = new SmartCardHSMCrypto(new Crypto());
    2342 	}
    2343 	return this.crypto;
    2344 }
    2345
    2346
    2347
    2348 /**
    2349  * @private
    2350  */
    2351 SmartCardHSM.prototype.getTokenInfo = function() {
    2352 	if (this.tokenInfo != undefined) {
    2353 		return this.tokenInfo;
    2354 	}
    2355
    2356 	if (!this.hasFile(SmartCardHSM.EF_TokenInfo)) {
    2357 		return;
    2358 	}
    2359
    2360 	var bin = this.readBinary(SmartCardHSM.EF_TokenInfo);
    2361 	this.tokenInfo = new ASN1(bin);
    2362 	return this.tokenInfo;
    2363 }
    2364
    2365
    2366
    2367 /**
    2368  * Get Token Label
    2369  *
    2370  * @type String
    2371  * @return the token label from CIAInfo
    2372  */
    2373 SmartCardHSM.prototype.getLabel = function() {
    2374 	var ti = this.getTokenInfo();
    2375 	if (!ti) {
    2376 		return;
    2377 	}
    2378
    2379 	var a = ti.find(0x80);
    2380 	if (!a) {
    2381 		return;
    2382 	}
    2383 	return a.value.toString(UTF8);
    2384 }
    2385
    2386
    2387
    2388 /**
    2389  * @private
    2390  */
    2391 SmartCardHSM.prototype.getStaticTokenInfo = function() {
    2392 	if (this.staticTokenInfo != undefined) {
    2393 		return this.staticTokenInfo;
    2394 	}
    2395
    2396 	if (!this.hasFile(SmartCardHSM.EF_StaticTokenInfo)) {
    2397 		return;
    2398 	}
    2399
    2400 	var bin = this.readBinary(SmartCardHSM.EF_StaticTokenInfo);
    2401 	this.staticTokenInfo = new ASN1(bin);
    2402 	return this.staticTokenInfo;
    2403 }
    2404
    2405
    2406
    2407 /**
    2408  * Get ProvisioningURL
    2409  *
    2410  * @type String
    2411  * @return the configured ProvisioningURL or undefined
    2412  */
    2413 SmartCardHSM.prototype.getProvisioningURL = function() {
    2414 	var ti = this.getStaticTokenInfo();
    2415 	if (!ti) {
    2416 		return;
    2417 	}
    2418
    2419 	var a = ti.find(0x80);
    2420 	if (!a) {
    2421 		return;
    2422 	}
    2423 	return a.value.toString(UTF8);
    2424 }
    2425
    2426
    2427
    2428 /**
    2429  * Get Key Check Value of Token Management Key
    2430  *
    2431  * @type ByteString
    2432  * @return the configured KCV of the Token Management Key or undefined
    2433  */
    2434 SmartCardHSM.prototype.getTokenManagementKeyKCV = function() {
    2435 	var ti = this.getStaticTokenInfo();
    2436 	if (!ti) {
    2437 		return;
    2438 	}
    2439
    2440 	var a = ti.find(0x81);
    2441 	if (!a) {
    2442 		return;
    2443 	}
    2444 	return a.value;
    2445 }
    2446
    2447
    2448
    2449 /**
    2450  * Get salt for SO-PIN derivation using  the Token Management Key
    2451  *
    2452  * @type ByteString
    2453  * @return the configured salt
    2454  */
    2455 SmartCardHSM.prototype.getTokenManagementKeySalt = function() {
    2456 	var ti = this.getStaticTokenInfo();
    2457 	if (!ti) {
    2458 		return;
    2459 	}
    2460
    2461 	var a = ti.find(0x82);
    2462 	if (!a) {
    2463 		return;
    2464 	}
    2465 	return a.value;
    2466 }
    2467
    2468
    2469
    2470 /**
    2471  * Create crypto object implementing access to the SmartCard-HSM
    2472  *
    2473  * @class Wrapper to provide Crypto interface to SmartCard-HSM
    2474  * @constructor
    2475  * @param {Crypto} crypto the backend crypto provider
    2476  */
    2477 function SmartCardHSMCrypto(crypto) {
    2478 	this.crypto = crypto;
    2479 }
    2480
    2481
    2482
    2483 /**
    2484  * Sign a message using the defined mechanism and key
    2485  *
    2486  * @param {HSMKey} key the private key
    2487  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
    2488  * @param {ByteString} message the message to be signed
    2489  * @type ByteString
    2490  * @return the signature
    2491  */
    2492 SmartCardHSMCrypto.prototype.sign = function(key, mech, message) {
    2493 	if (key instanceof SmartCardHSMKey) {
    2494 		return key.sign(mech, message);
    2495 	} else {
    2496 		return this.crypto.sign(key, mech, message);
    2497 	}
    2498 }
    2499
    2500
    2501
    2502 /**
    2503  * Decrypt a message using the defined mechanism and key
    2504  *
    2505  * @param {HSMKey} key the private key
    2506  * @param {Number} mech the mechanism (e.g. Crypto.RSA_PKCS1)
    2507  * @param {ByteString} data the cryptogram
    2508  * @param {ByteString} iv the initialization vector for symmetric ciphers
    2509  * @type ByteString
    2510  * @return the plain text
    2511  */
    2512 SmartCardHSMCrypto.prototype.decrypt = function(key, mech, data, iv) {
    2513 	if (key instanceof SmartCardHSMKey) {
    2514 		return key.decrypt(mech, data);
    2515 	} else {
    2516 		return this.crypto.decrypt(key, mech, data, iv);
    2517 	}
    2518 }
    2519
    2520
    2521
    2522 /**
    2523  * Verify a message using the defined mechanism and key
    2524  *
    2525  * @param {Key} key the public key
    2526  * @param {Number} mech the mechanism (e.g. Crypto.ECDSA)
    2527  * @param {ByteString} message the message to be signed
    2528  * @param {ByteString} signature the signature to verify
    2529  * @type Boolean
    2530  * @return true if signature is valid
    2531  */
    2532 SmartCardHSMCrypto.prototype.verify = function(key, mech, message, signature) {
    2533 	return this.crypto.verify(key, mech, message, signature);
    2534 }
    2535
    2536
    2537
    2538 /**
    2539  * Create a key access object
    2540  *
    2541  * @class Class implementing key access
    2542  * @param {SmartCardHSM} sc the card access object
    2543  * @param {Number} id the key identifier
    2544  */
    2545 function SmartCardHSMKey(sc, id) {
    2546 	this.sc = sc;
    2547 	this.id = id;
    2548 	if (this.sc.useExternalHashInECDSA) {
    2549 		this.crypto = new Crypto();
    2550 	}
    2551 }
    2552
    2553 exports.SmartCardHSMKey = SmartCardHSMKey;
    2554
    2555
    2556 /**
    2557  * Set the PKCS#15 private key description
    2558  *
    2559  * @param {ASN1} desc the description
    2560  */
    2561 SmartCardHSMKey.prototype.setDescription = function(desc) {
    2562 	this.desc = desc;
    2563 }
    2564
    2565
    2566
    2567 /**
    2568  * Return the key identifier
    2569  *
    2570  * @type Number
    2571  * @return the key identifier
    2572  */
    2573 SmartCardHSMKey.prototype.getId = function() {
    2574 	return this.id;
    2575 }
    2576
    2577
    2578
    2579 /**
    2580  * Return the key label as encoded in the PKCS#15 structure
    2581  *
    2582  * @type String
    2583  * @return the key label
    2584  */
    2585 SmartCardHSMKey.prototype.getLabel = function() {
    2586 	if (this.desc == undefined) {
    2587 		return undefined;
    2588 	}
    2589 	if ((this.desc.get(0).elements == 0) || this.desc.get(0).get(0).tag != 0x0C) {
    2590 		return undefined;
    2591 	}
    2592
    2593 	return this.desc.get(0).get(0).value.toString(UTF8);
    2594 }
    2595
    2596
    2597
    2598 /**
    2599  * Return the key id as encoded in the PKCS#15 structure
    2600  *
    2601  * @type ByteString
    2602  * @return the key identifier
    2603  */
    2604 SmartCardHSMKey.prototype.getPKCS15Id = function() {
    2605 	if (this.desc == undefined) {
    2606 		return undefined;
    2607 	}
    2608 	return this.desc.get(1).get(0).value;
    2609 }
    2610
    2611
    2612
    2613 /**
    2614  * Return the key size in bits
    2615  *
    2616  * @type Number
    2617  * @return the key size in bits
    2618  */
    2619 SmartCardHSMKey.prototype.getSize = function() {
    2620 	if (this.desc == undefined) {
    2621 		return undefined;
    2622 	}
    2623 //	GPSystem.log(GPSystem.DEBUG, module.id, this.desc);
    2624 	if (this.desc.get(2).elements > 1) {	// Fix a bug from early versions
    2625 		return this.desc.get(2).get(1).value.toUnsigned();
    2626 	}
    2627
    2628 	if (this.desc.tag == 0xA8) {
    2629 		var size = this.desc.get(2).get(0).get(0).value.toUnsigned();
    2630 	} else {
    2631 		var a1 = this.desc.find(0xA1);
    2632 		var size = a1.get(0).get(1).value.toUnsigned();
    2633
    2634 		if (size == 528) {
    2635 			size = 521;		// Fix bug in OpenSCDP returning the wrong key size for secp521 keys
    2636 		}
    2637 	}
    2638
    2639 	return size;
    2640 }
    2641
    2642
    2643
    2644 /**
    2645  * Return the key type
    2646  *
    2647  * @type String
    2648  * @return the key type
    2649  */
    2650 SmartCardHSMKey.prototype.getType = function() {
    2651 	if (this.desc == undefined) {
    2652 		return undefined;
    2653 	}
    2654
    2655 	if (this.desc.tag == 0xA0) {
    2656 		return "EC";
    2657 	} else if (this.desc.tag == 0x30) {
    2658 		return "RSA";
    2659 	} else if (this.desc.tag == 0xA8) {
    2660 		return "AES";
    2661 	}
    2662
    2663 	return undefined;
    2664 }
    2665
    2666
    2667
    2668 /**
    2669  * Sign data using a key in the SmartCard-HSM
    2670  *
    2671  * @param {Number} mech the signing mechanism
    2672  * @param {ByteString} data to be signed
    2673  * @type ByteString
    2674  * @return the signature
    2675  */
    2676 SmartCardHSMKey.prototype.sign = function(mech, data) {
    2677 	var algo;
    2678 	if (mech) {
    2679 		switch(mech) {
    2680 		case Crypto.RSA:
    2681 			algo = 0x20;
    2682 			break;
    2683 		case Crypto.RSA_SHA1:
    2684 			algo = 0x31;
    2685 			break;
    2686 		case Crypto.RSA_SHA224:
    2687 			algo = 0x32;
    2688 			break;
    2689 		case Crypto.RSA_SHA256:
    2690 			algo = 0x33;
    2691 			break;
    2692 		case Crypto.RSA_SHA384:
    2693 			algo = 0x34;
    2694 			break;
    2695 		case Crypto.RSA_SHA512:
    2696 			algo = 0x35;
    2697 			break;
    2698 		case Crypto.RSA_PKCS1:
    2699 			if (this.sc.major && this.sc.major >= 4) {
    2700 				algo = 0x30;
    2701 			} else {
    2702 				algo = 0x20;
    2703 				var keysize = this.getSize();
    2704 				if (!keysize) {
    2705 					throw new GPError(module.id, GPError.INVALID_DATA, 0, "Can't determine key size");
    2706 				}
    2707 				data = PKCS1.encode_EMSA_V15(keysize, data);
    2708 			}
    2709 			break;
    2710 		case Crypto.RSA_PSS:
    2711 		case 0x80:
    2712 			algo = 0x40;
    2713 			break;
    2714 		case Crypto.RSA_PSS_SHA1:
    2715 			algo = 0x41;
    2716 			break;
    2717 		case Crypto.RSA_PSS_SHA224:
    2718 			algo = 0x42;
    2719 			break;
    2720 		case Crypto.RSA_PSS_SHA256:
    2721 			algo = 0x43;
    2722 			break;
    2723 		case Crypto.RSA_PSS_SHA384:
    2724 			algo = 0x44;
    2725 			break;
    2726 		case Crypto.RSA_PSS_SHA512:
    2727 			algo = 0x45;
    2728 			break;
    2729 		case Crypto.ECDSA:
    2730 			algo = 0x70;
    2731 			break;
    2732 		case Crypto.ECDSA_SHA1:
    2733 			if (this.sc.useExternalHashInECDSA) {
    2734 				algo = 0x70;
    2735 				var data = this.crypto.digest(Crypto.SHA_1, data);
    2736 			} else {
    2737 				algo = 0x71;
    2738 			}
    2739 			break;
    2740 		case Crypto.ECDSA_SHA224:
    2741 			if (this.sc.useExternalHashInECDSA) {
    2742 				algo = 0x70;
    2743 				var data = this.crypto.digest(Crypto.SHA_224, data);
    2744 			} else {
    2745 				algo = 0x72;
    2746 			}
    2747 			break;
    2748 		case Crypto.ECDSA_SHA256:
    2749 			if (this.sc.useExternalHashInECDSA) {
    2750 				algo = 0x70;
    2751 				var data = this.crypto.digest(Crypto.SHA_256, data);
    2752 			} else {
    2753 				algo = 0x73;
    2754 			}
    2755 			break;
    2756 		case Crypto.ECDSA_SHA384:
    2757 			if (this.sc.useExternalHashInECDSA) {
    2758 				algo = 0x70;
    2759 				var data = this.crypto.digest(Crypto.SHA_384, data);
    2760 			} else {
    2761 				algo = 0x74;
    2762 			}
    2763 			break;
    2764 		case Crypto.ECDSA_SHA512:
    2765 			if (this.sc.useExternalHashInECDSA) {
    2766 				algo = 0x70;
    2767 				var data = this.crypto.digest(Crypto.SHA_512, data);
    2768 			} else {
    2769 				algo = 0x75;
    2770 			}
    2771 			break;
    2772 		case Crypto.AES_CMAC:
    2773 			return this.sc.deriveSymmetricKey(this.id, SmartCardHSM.ALG_CMAC, data);
    2774 		default:
    2775 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
    2776 		}
    2777 	}
    2778
    2779 	return this.sc.sign(this.id, algo, data);
    2780 }
    2781
    2782
    2783
    2784 /**
    2785  * Decrypt data using a key in the SmartCard-HSM
    2786  *
    2787  * @param {Number} mech the decipher mechanism
    2788  * @param {ByteString} data to be deciphered
    2789  * @type ByteString
    2790  * @return the plain message
    2791  */
    2792 SmartCardHSMKey.prototype.decrypt = function(mech, data) {
    2793 	var algo;
    2794 	if (mech) {
    2795 		switch(mech) {
    2796 		case Crypto.RSA:
    2797 			break;
    2798 		case Crypto.RSA_PKCS1:
    2799 			break;
    2800 		case Crypto.RSA_OAEP_SHA224:
    2801 			algo = Crypto.SHA_224;
    2802 			break;
    2803 		case Crypto.RSA_OAEP_SHA256:
    2804 			algo = Crypto.SHA_256;
    2805 			break;
    2806 		case Crypto.RSA_OAEP_SHA384:
    2807 			algo = Crypto.SHA_384;
    2808 			break;
    2809 		case Crypto.RSA_OAEP_SHA512:
    2810 			algo = Crypto.SHA_512;
    2811 			break;
    2812 		default:
    2813 			throw new GPError("SmartCardHSMKey", GPError.INVALID_DATA, mech, "Unsupported crypto mechanism");
    2814 		}
    2815 	}
    2816
    2817 	var em = this.sc.decipher(this.id, 0x21, data);
    2818
    2819 	var plain = em;
    2820
    2821 	if (mech != Crypto.RSA) {
    2822 		if (mech == Crypto.RSA_PKCS1) {
    2823 			var plain = PKCS1.decode_EME_V15(em);
    2824 		} else {
    2825 			var crypto = this.sc.getCrypto().crypto;
    2826
    2827 			var plain = PKCS1.decode_EME_OAEP(crypto, null, algo, em);
    2828 		}
    2829
    2830 		if (!plain) {
    2831 			throw new GPError("SmartCardHSMKey", GPError.CRYPTO_FAILED, mech, "Decryption failed");
    2832 		}
    2833 	}
    2834
    2835 	return plain;
    2836 }
    2837
    2838
    2839
    2840 /**
    2841  * Return human readable string
    2842  */
    2843 SmartCardHSMKey.prototype.toString = function() {
    2844 	return "SmartCardHSMKey(id=" + this.id + ")";
    2845 }
    2846
    2847
    2848
    2849 /**
    2850  * Initialize SmartCard-HSM
    2851  *
    2852  * @class Class implementing the device initialization methods
    2853  * @param {Card} card the card object
    2854  */
    2855 function SmartCardHSMInitializer(card) {
    2856 	this.card = card;
    2857 	this.initializationCode = new ByteString("57621880", ASCII);
    2858 	this.userPIN = new ByteString("648219", ASCII);
    2859 	this.userPINSet = false;
    2860 	this.useDefaultUserPIN = true;
    2861 	this.retryCounterInitial = 3;
    2862 	this.options = 0x0001;
    2863 	this.keyshares = -1;
    2864 	this.keyDomains = -1;
    2865 	this.numberOfPublicKeys = 0;
    2866 	this.requiredPublicKeysForAuthentication = 0;
    2867 	this.bioslot = [];
    2868 	this.label = undefined;
    2869 }
    2870
    2871 exports.SmartCardHSMInitializer = SmartCardHSMInitializer;
    2872
    2873
    2874
    2875 /**
    2876  * Set the initialization code
    2877  *
    2878  * @param {ByteString} initializationCode an 8 byte code
    2879  */
    2880 SmartCardHSMInitializer.prototype.setInitializationCode = function(initializationCode) {
    2881 	if (!(initializationCode instanceof ByteString)) {
    2882 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must be a ByteString");
    2883 	}
    2884 	if (initializationCode.length != 8) {
    2885 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "initializationCode must have 8 bytes");
    2886 	}
    2887
    2888 	this.initializationCode = initializationCode;
    2889 }
    2890
    2891
    2892
    2893 /**
    2894  * Set the User PIN
    2895  *
    2896  * @param {ByteString} userPIN a 6 to 16 byte code
    2897  */
    2898 SmartCardHSMInitializer.prototype.setUserPIN = function(userPIN) {
    2899 	if (!(userPIN instanceof ByteString)) {
    2900 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be a ByteString");
    2901 	}
    2902 	if ((userPIN.length < 6) || (userPIN.length > 16)) {
    2903 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "userPIN must be between 6 and 16 bytes");
    2904 	}
    2905
    2906 	this.userPIN = userPIN;
    2907 	this.userPINSet = true;
    2908 	this.useDefaultUserPIN = false;
    2909 }
    2910
    2911
    2912
    2913 /**
    2914  * Set the retry counter
    2915  *
    2916  * The SmartCard-HSM enforces a retry counter <= 3 for PIN length 6
    2917  * The SmartCard-HSM enforces a retry counter <= 5 for PIN length 7
    2918  * The SmartCard-HSM enforces a retry counter <= 10 for PIN length larger than 7
    2919  *
    2920  * @param {Number} retryCounterInitial in the range 1 to 10.
    2921  */
    2922 SmartCardHSMInitializer.prototype.setRetryCounterInitial = function(retryCounterInitial) {
    2923 	if (typeof(retryCounterInitial) != "number") {
    2924 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be a number");
    2925 	}
    2926 	if ((retryCounterInitial < 1) || (retryCounterInitial > 10)) {
    2927 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "retryCounterInitial must be between 1 and 10");
    2928 	}
    2929 	this.retryCounterInitial = retryCounterInitial;
    2930 }
    2931
    2932
    2933
    2934 /**
    2935  * Set the number of DKEK shares
    2936  *
    2937  * @param {Number} keyshares number of DKEK shares in the range 0 to 255
    2938  */
    2939 SmartCardHSMInitializer.prototype.setDKEKShares = function(keyshares) {
    2940 	if (typeof(keyshares) != "number") {
    2941 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be a number");
    2942 	}
    2943 	if ((keyshares < 0) || (keyshares > 255)) {
    2944 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyshares must be between 0 and 255");
    2945 	}
    2946 	this.keyshares = keyshares;
    2947 	this.keyDomains = -1;
    2948 }
    2949
    2950
    2951
    2952 /**
    2953  * Set the number of key domains
    2954  *
    2955  * @param {Number} keyDomains number of key domains
    2956  */
    2957 SmartCardHSMInitializer.prototype.setKeyDomains = function(keyDomains) {
    2958 	if (typeof(keyDomains) != "number") {
    2959 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "keyDomains must be a number");
    2960 	}
    2961
    2962 	this.keyDomains = keyDomains;
    2963 	this.keyshares = -1;
    2964 }
    2965
    2966
    2967
    2968 /**
    2969  * Enable or disable RESET RETRY COUNTER command
    2970  *
    2971  * @param {Boolean} enable true (default) to allow RESET RETRY COUNTER command to reset user PIN using the initialization code
    2972  */
    2973 SmartCardHSMInitializer.prototype.setResetRetryCounterMode = function(enable) {
    2974 	if (typeof(enable) == "undefined") {
    2975 		var enable = false;
    2976 	}
    2977
    2978 	this.options = (this.options & 0xFFFE) + (enable ? 1 : 0);
    2979 }
    2980
    2981
    2982
    2983 /**
    2984  * Enable or disable transport PIN mode
    2985  *
    2986  * @param {Boolean} enable true (non-default) to set user PIN to transport state
    2987  */
    2988 SmartCardHSMInitializer.prototype.setTransportPINMode = function(enable) {
    2989 	if (typeof(enable) == "undefined") {
    2990 		var enable = true;
    2991 	}
    2992
    2993 	this.options = (this.options & 0xFFFD) + (enable ? 2 : 0);
    2994 }
    2995
    2996
    2997
    2998 /**
    2999  * Enable or disable session PIN mode
    3000  *
    3001  * @param {Number} 0 - disable, 1 - enable with clear-on-reset 3 - enable with explicit clearing
    3002  */
    3003 SmartCardHSMInitializer.prototype.setSessionPINMode = function(mode) {
    3004 	assert(typeof(mode) == "number", "Argument mode must be number");
    3005 	assert(mode >= 0 && mode <= 3 && mode != 2, "Argument mode must be 0, 1 or 3");
    3006
    3007 	this.options = (this.options & 0xFFF3) + (mode << 2);
    3008 }
    3009
    3010
    3011
    3012 /**
    3013  * Enable or disable replacing of a PKA key
    3014  *
    3015  * @param {Boolean} enable true (non-default) to allow replacing of a PKA key
    3016  */
    3017 SmartCardHSMInitializer.prototype.setReplacePKAKeyMode = function(enable) {
    3018 	if (typeof(enable) == "undefined") {
    3019 		var enable = false;
    3020 	}
    3021
    3022 	this.options = (this.options & 0xFFF7) + (enable ? 8 : 0);
    3023 }
    3024
    3025
    3026
    3027 /**
    3028  * Enable the combined authentication mode of user pin and public key authentication.
    3029  *
    3030  * @param {Boolean} enable true (non-default) to require public key authentication and user authentication
    3031  */
    3032 SmartCardHSMInitializer.prototype.setCombinedAuthenticationMode = function(enable) {
    3033 	if (typeof(enable) == "undefined") {
    3034 		var enable = false;
    3035 	}
    3036
    3037 	this.options = (this.options & 0xFFEF) + (enable ? 16 : 0);
    3038 }
    3039
    3040
    3041
    3042 /**
    3043  * If enabled RESET RETRY COUNTER only resets the error counter.
    3044  * Otherwise  RRC allows changing the PIN
    3045  *
    3046  * @param {Boolean} resetOnly true to only reset the error counter, false otherwise (default)
    3047  */
    3048 SmartCardHSMInitializer.prototype.setResetRetryCounterResetOnlyMode = function(resetOnly) {
    3049 	if (typeof(resetOnly) == "undefined") {
    3050 		var resetOnly = false;
    3051 	}
    3052
    3053 	this.options = (this.options & 0xFFDF) + (resetOnly ? 32 : 0);
    3054 }
    3055
    3056
    3057
    3058 /**
    3059  * Set parameter for public key authentication with n-of-m scheme, namely the values for n and m
    3060  *
    3061  * @param {Number} requiredPublicKeysForAuthentication number of key that must be authenticated for access
    3062  * @param {Number} numberOfPublicKeys to register
    3063  */
    3064 SmartCardHSMInitializer.prototype.setPublicKeyAuthenticationParameter = function(requiredPublicKeysForAuthentication, numberOfPublicKeys) {
    3065 	if ((numberOfPublicKeys < 1) || (numberOfPublicKeys > 90)) {
    3066 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 1, "numberOfPublicKeys must be between 1 and 90");
    3067 	}
    3068 	if ((requiredPublicKeysForAuthentication < 1) || (requiredPublicKeysForAuthentication > numberOfPublicKeys)) {
    3069 		throw new GPError("SmartCardHSMInitializer", GPError.INVALID_DATA, 2, "requiredPublicKeysForAuthentication must be between 1 and " + numberOfPublicKeys);
    3070 	}
    3071 	this.numberOfPublicKeys = numberOfPublicKeys;
    3072 	this.requiredPublicKeysForAuthentication = requiredPublicKeysForAuthentication;
    3073 	this.useDefaultUserPIN = false;
    3074 }
    3075
    3076
    3077
    3078 /**
    3079  * Select the biometric matching server for a one of the biometric templates
    3080  *
    3081  * @param {Number} slot either 0 or 1 for first or second template
    3082  * @param {ByteString} aid the application identifier of the on-card biometric server
    3083  * @param {Number} param one byte parameter passed to the server during initialization
    3084  */
    3085 SmartCardHSMInitializer.prototype.setBioTemplate = function(slot, aid, param) {
    3086 	assert(typeof(slot) == "number", "slot must be a number");
    3087 	assert(slot >= 0 && slot <= 1, "slot must be either 0 or 1");
    3088 	assert(aid instanceof ByteString, "aid must be a ByteString");
    3089 	assert(typeof(param) == "number", "param must be a number");
    3090 	assert(param >= 0 && param <= 255, "param must be between 0 and 255");
    3091
    3092 	this.bioslot[slot] = { aid: aid, param: param };
    3093 	this.useDefaultUserPIN = false;
    3094 }
    3095
    3096
    3097
    3098 /**
    3099  * Set the label to be written to a minimal CIAInfo in EF 2F03
    3100  *
    3101  * @param {String} label the label
    3102  */
    3103 SmartCardHSMInitializer.prototype.setLabel = function(label) {
    3104 	this.label = label;
    3105 }
    3106
    3107
    3108
    3109 /**
    3110  * Set the provisioning URL to be written to fixed parameter in CB00.
    3111  *
    3112  * @param {String} provisioningURL the URL at which this SE will be provisioned
    3113  */
    3114 SmartCardHSMInitializer.prototype.setProvisioningURL = function(provisioningURL) {
    3115 	this.provisioningURL = provisioningURL;
    3116 }
    3117
    3118
    3119
    3120 /**
    3121  * Set the key check value of the token management key and the optional salt
    3122  * used for SO-PIN derivation
    3123  *
    3124  * @param {ByteString} kcv the key check value of the token management key
    3125  * @param {ByteString} salt the salt used to derive the SO-PIN
    3126  */
    3127 SmartCardHSMInitializer.prototype.setTokenManagementKey = function(kcv, salt) {
    3128 	this.tokenManagementKeyKCV = kcv;
    3129 	this.tokenManagementKeySalt = salt;
    3130 }
    3131
    3132
    3133
    3134 /**
    3135  * Perform Initialization
    3136  */
    3137 SmartCardHSMInitializer.prototype.initialize = function() {
    3138 	var s = new ASN1(0x30,	new ASN1(0x80, ByteString.valueOf(this.options, 2)));
    3139
    3140 	if (this.userPINSet || this.useDefaultUserPIN) {
    3141 		s.add(new ASN1(0x81, this.userPIN));
    3142 	}
    3143
    3144 	s.add(new ASN1(0x82, this.initializationCode));
    3145
    3146 	if (this.userPINSet || this.useDefaultUserPIN) {
    3147 		s.add(new ASN1(0x91, ByteString.valueOf(this.retryCounterInitial)));
    3148 	}
    3149
    3150 	if (this.keyshares != -1) {
    3151 		s.add(new ASN1(0x92, ByteString.valueOf(this.keyshares)));
    3152 	}
    3153
    3154 	if (this.keyDomains != -1) {
    3155 		s.add(new ASN1(0x97, ByteString.valueOf(this.keyDomains)));
    3156 	}
    3157
    3158 	if (this.numberOfPublicKeys > 0) {
    3159 		s.add(new ASN1(0x93, ByteString.valueOf(this.numberOfPublicKeys).concat(ByteString.valueOf(this.requiredPublicKeysForAuthentication))));
    3160 	}
    3161
    3162 	if (this.bioslot[0]) {
    3163 		var o = this.bioslot[0];
    3164 		s.add(new ASN1(0x95, ByteString.valueOf(o.param).concat(o.aid)));
    3165 	}
    3166
    3167 	if (this.bioslot[1]) {
    3168 		var o = this.bioslot[1];
    3169 		s.add(new ASN1(0x96, ByteString.valueOf(o.param).concat(o.aid)));
    3170 	}
    3171
    3172 	this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000, 0x6A84]);
    3173
    3174 	if (this.card.SW == 0x6A84) {
    3175 		// Due to the nature of the JCRE, a first call to initialize may run out of memory,
    3176 		// as the garbage collector for the removed objects is only run during the next
    3177 		// APDU invocation.
    3178 		this.card.sendSecMsgApdu(Card.ALL, 0x80, 0x50, 0x00, 0x00, s.value, [0x9000]);
    3179 	}
    3180
    3181 	if (this.label) {
    3182 		var a = new ASN1(0x30,
    3183 				new ASN1(0x54, new ByteString("0000", HEX)),
    3184 				new ASN1(0x53,
    3185 					new ASN1(0x30,
    3186 						new ASN1(0x02, new ByteString("00", HEX)),
    3187 						new ASN1(0x80, new ByteString(this.label, UTF8)),
    3188 						new ASN1(0x03, new ByteString("0500", HEX)))
    3189 				)
    3190 			);
    3191
    3192 		var p1 = SmartCardHSM.EF_TokenInfo.byteAt(0);
    3193 		var p2 = SmartCardHSM.EF_TokenInfo.byteAt(1);
    3194 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
    3195 	}
    3196
    3197 	if (this.provisioningURL || this.tokenManagementKeyKCV || this.tokenManagementKeySalt) {
    3198 		var l = new ASN1(ASN1.SEQUENCE);
    3199 		if (this.provisioningURL) {
    3200 			l.add(new ASN1(0x80, new ByteString(this.provisioningURL, UTF8)));
    3201 		}
    3202 		if (this.tokenManagementKeyKCV) {
    3203 			l.add(new ASN1(0x81, this.tokenManagementKeyKCV));
    3204 		}
    3205 		if (this.tokenManagementKeySalt) {
    3206 			l.add(new ASN1(0x82, this.tokenManagementKeySalt));
    3207 		}
    3208
    3209 		var a = new ASN1(0x30,
    3210 				new ASN1(0x54, new ByteString("0000", HEX)),
    3211 				new ASN1(0x53, l)
    3212 			);
    3213
    3214 		var p1 = SmartCardHSM.EF_StaticTokenInfo.byteAt(0);
    3215 		var p2 = SmartCardHSM.EF_StaticTokenInfo.byteAt(1);
    3216 		this.card.sendSecMsgApdu(Card.ALL, 0x00, 0xD7, p1, p2, a.value, [0x9000]);
    3217 	}
    3218 }
    3219
    3220
    3221
    3222 /**
    3223  * Create a key specification generator instance
    3224  *
    3225  * @class Class implementing an encoder for the C-Data required in GENERATE ASYMMETRIC KEY PAIR
    3226  * @param {Number} keytype must be either Crypto.RSA, Crypto.EC or Crypto.AES
    3227  * @param {Number/Key} keysizeOrDP must be 1024, 1536, 2048, 3072 or 4096 for RSA, 128, 192 or 256 for AES and key object with Key.ECC_CURVE_OID set for EC
    3228  */
    3229 function SmartCardHSMKeySpecGenerator(keytype, keysizeOrDP) {
    3230 	this.keytype = keytype;
    3231
    3232 	switch(keytype) {
    3233 		case Crypto.RSA:
    3234 			if (typeof(keysizeOrDP) != "number") {
    3235 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for RSA keys");
    3236 			}
    3237 			this.keysize = keysizeOrDP;
    3238 			this.defaultAlgo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
    3239 			break;
    3240 		case Crypto.EC:
    3241 			if ((typeof(keysizeOrDP) != "object") || !(keysizeOrDP instanceof Key)) {
    3242 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be a Key instance");
    3243 			}
    3244 			this.domainParameter = keysizeOrDP;
    3245 			this.defaultAlgo = new ByteString("id-TA-ECDSA-SHA-256", OID);
    3246 			break;
    3247 		case Crypto.AES:
    3248 			if (typeof(keysizeOrDP) != "number") {
    3249 				throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keysizeIdDP must be of a number for AES keys");
    3250 			}
    3251 			this.keysize = keysizeOrDP;
    3252 			break;
    3253 		default:
    3254 			throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 3, "keytype must be Crypto.RSA or Crypto.EC");
    3255 	}
    3256 	this.CHR = new PublicKeyReference("UTDUMMY00001");
    3257 	this.innerCAR = new PublicKeyReference("UTDUMMY00001");
    3258 }
    3259
    3260 exports.SmartCardHSMKeySpecGenerator = SmartCardHSMKeySpecGenerator;
    3261
    3262
    3263
    3264 /**
    3265  * Set key use counter for key
    3266  *
    3267  * @param {keyUseCounter} keyUseCounter in the range 1 to 2^64 - 2
    3268  */
    3269 SmartCardHSMKeySpecGenerator.prototype.setKeyUseCounter = function(keyUseCounter) {
    3270 	if ((keyUseCounter < 0) || (keyUseCounter >= 0xFFFFFFFF)) {
    3271 		throw new GPError("SmartCardHSMKeySpecGenerator", GPError.INVALID_DATA, 1, "keyUseCounter must be between 0 and 0xFFFFFFFF");
    3272 	}
    3273 	this.keyUseCounter = keyUseCounter;
    3274 }
    3275
    3276
    3277
    3278 /**
    3279  * Set key domain
    3280  *
    3281  * @param {Number} keyDomain the key domain to which the key shall be added
    3282  */
    3283 SmartCardHSMKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
    3284 	this.keyDomain = keyDomain;
    3285 }
    3286
    3287
    3288
    3289 /**
    3290  * Set wrapping key
    3291  *
    3292  * @param {Number} wrappingKey the key to used for wrapping a newly generated symmetric key
    3293  */
    3294 SmartCardHSMKeySpecGenerator.prototype.setWrappingKey = function(wrappingKey) {
    3295 	this.wrappingKey = wrappingKey;
    3296 }
    3297
    3298
    3299
    3300 /**
    3301  * Set algorithm list
    3302  *
    3303  * @param {ByteString} algorithms the list of algorithms allowed for this key
    3304  */
    3305 SmartCardHSMKeySpecGenerator.prototype.setAlgorithms = function(algorithms) {
    3306 	this.algorithms = algorithms;
    3307 }
    3308
    3309
    3310
    3311 /**
    3312  * Set certificate holder reference for key
    3313  *
    3314  * @param {PublicKeyReference} CHR certificate holder reference
    3315  */
    3316 SmartCardHSMKeySpecGenerator.prototype.setCHR = function(CHR) {
    3317 	this.CHR = CHR;
    3318 }
    3319
    3320
    3321
    3322 /**
    3323  * Set certificate holder reference of CA this request shall be sent to
    3324  *
    3325  * @param {PublicKeyReference} CAR certificate holder reference
    3326  */
    3327 SmartCardHSMKeySpecGenerator.prototype.setInnerCAR = function(CAR) {
    3328 	this.innerCAR = CAR;
    3329 }
    3330
    3331
    3332
    3333 /**
    3334  * Set holder reference of the key signing this request
    3335  *
    3336  * @param {PublicKeyReference} CAR certificate holder reference
    3337  */
    3338 SmartCardHSMKeySpecGenerator.prototype.setOuterCAR = function(CAR) {
    3339 	this.outerCAR = CAR;
    3340 }
    3341
    3342
    3343
    3344 /**
    3345  * @private
    3346  */
    3347 SmartCardHSMKeySpecGenerator.prototype.encodeRSAKeySpec = function() {
    3348 	var p = new ASN1("Public Key", 0x7F49,
    3349 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
    3350 			new ASN1("Public Key Exponent", 0x82, ByteString.valueOf(65537)),
    3351 			new ASN1("Key Size", 0x02, ByteString.valueOf(this.keysize))
    3352 		);
    3353 	return p;
    3354 }
    3355
    3356
    3357
    3358 /**
    3359  * @private
    3360  */
    3361 SmartCardHSMKeySpecGenerator.prototype.encodeECKeySpec = function() {
    3362 	// Encode G
    3363 	var bb = new ByteBuffer();
    3364 	// uncompressed encoding
    3365 	bb.append(new ByteString("04", HEX));
    3366 	bb.append(this.domainParameter.getComponent(Key.ECC_GX));
    3367 	bb.append(this.domainParameter.getComponent(Key.ECC_GY));
    3368 	var G = bb.toByteString();
    3369
    3370 	var p = new ASN1("Public Key", 0x7F49,
    3371 			new ASN1("Object Identifier", 0x06, this.defaultAlgo),
    3372 			new ASN1("Prime Modulus", 0x81, this.domainParameter.getComponent(Key.ECC_P)),
    3373 			new ASN1("First coefficient a", 0x82, this.domainParameter.getComponent(Key.ECC_A)),
    3374 			new ASN1("Second coefficient b", 0x83, this.domainParameter.getComponent(Key.ECC_B)),
    3375 			new ASN1("Base Point G", 0x84, G),
    3376 			new ASN1("Order of the base point", 0x85, this.domainParameter.getComponent(Key.ECC_N)),
    3377 			new ASN1("Cofactor f", 0x87, SmartCardHSM.stripLeadingZeros(this.domainParameter.getComponent(Key.ECC_H)))
    3378 		);
    3379 	return p;
    3380 }
    3381
    3382
    3383
    3384 /**
    3385  * @private
    3386  */
    3387 SmartCardHSMKeySpecGenerator.prototype.encodeKeySpec = function() {
    3388 	if (this.keytype == Crypto.RSA) {
    3389 		return this.encodeRSAKeySpec();
    3390 	} else {
    3391 		return this.encodeECKeySpec();
    3392 	}
    3393 }
    3394
    3395
    3396
    3397 /**
    3398  * Return the encoded key specification
    3399  *
    3400  * @type ByteString
    3401  * @return the encoded C-Data for GENERATE ASYMMETRIC KEY PAIR
    3402  */
    3403 SmartCardHSMKeySpecGenerator.prototype.encode = function() {
    3404 	var t = new ASN1(0x30);
    3405
    3406 	if (this.keytype != Crypto.AES) {
    3407 		t.add(new ASN1("CPI", 0x5F29, new ByteString("00", HEX)));
    3408
    3409 		if ((typeof(this.innerCAR) != "undefined") && (this.innerCAR)) {
    3410 			t.add(new ASN1("CAR", 0x42, this.innerCAR.getBytes()));
    3411 		}
    3412
    3413 		t.add(this.encodeKeySpec());
    3414 		t.add(new ASN1("CHR", 0x5F20, this.CHR.getBytes()));
    3415
    3416 		if (typeof(this.outerCAR) != "undefined") {
    3417 			t.add(new ASN1("OuterCAR", 0x45, this.outerCAR.getBytes()));
    3418 		}
    3419 	}
    3420
    3421 	if (typeof(this.keyUseCounter) != "undefined") {
    3422 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
    3423 	}
    3424
    3425 	if (typeof(this.algorithms) != "undefined") {
    3426 		t.add(new ASN1("Algorithms", 0x91, this.algorithms));
    3427 	}
    3428
    3429 	if (typeof(this.keyDomain) != "undefined") {
    3430 		t.add(new ASN1("KeyDomain", 0x92, ByteString.valueOf(this.keyDomain)));
    3431 	}
    3432
    3433 	if (typeof(this.wrappingKey) != "undefined") {
    3434 		t.add(new ASN1("Wrapping Key", 0x93, ByteString.valueOf(this.wrappingKey)));
    3435 	}
    3436
    3437 	return t.value;
    3438 }
    3439
    3440
    3441
    3442 /**
    3443  * Create a key specification generator instance for AES keys
    3444  *
    3445  * @class Class implementing an encoder for the C-Data required in Generate Symmetric Key
    3446  * @param {ByteString} allowedAlgorithms the list of allowed algorithm identifier
    3447  */
    3448 function SmartCardHSMSymmetricKeySpecGenerator(allowedAlgorithms) {
    3449 	this.algorithms = allowedAlgorithms;
    3450 }
    3451
    3452 exports.SmartCardHSMSymmetricKeySpecGenerator = SmartCardHSMSymmetricKeySpecGenerator;
    3453
    3454
    3455
    3456 /**
    3457  * Set key domain
    3458  *
    3459  * @param {Number} keyDomain the key domain to which the key shall be added
    3460  */
    3461 SmartCardHSMSymmetricKeySpecGenerator.prototype.setKeyDomain = function(keyDomain) {
    3462 	this.keyDomain = keyDomain;
    3463 }
    3464
    3465
    3466
    3467 /**
    3468  * Return the encoded AES key specification
    3469  *
    3470  * @type ByteString
    3471  * @return the encoded C-Data for Generate Symmetric Key
    3472  */
    3473 SmartCardHSMSymmetricKeySpecGenerator.prototype.encode = function() {
    3474 	var t = new ASN1(0x30);
    3475
    3476 	t.add(new ASN1("Algorithms", 0x91, this.algorithms));
    3477
    3478 	if (typeof(this.keyUseCounter) != "undefined") {
    3479 		t.add(new ASN1("Key use counter", 0x90, ByteString.valueOf(this.keyUseCounter, 4)));
    3480 	}
    3481
    3482 	if (typeof(this.keyDomain) != "undefined") {
    3483 		t.add(new ASN1("Key Domain", 0x92, ByteString.valueOf(this.keyDomain)));
    3484 	}
    3485
    3486 	if (typeof(this.wrappingKey) != "undefined") {
    3487 		t.add(new ASN1("Wrapping Key", 0x93, this.wrappingKey));
    3488 	}
    3489
    3490 	return t.value;
    3491 }
    3492
    3493
    3494
    3495 SmartCardHSM.test = function() {
    3496 	var crypto = new Crypto();
    3497 	var card = new Card(_scsh3.reader);
    3498 	var sc = new SmartCardHSM(card);
    3499
    3500 	var sci = new SmartCardHSMInitializer(card);
    3501 	sci.initialize();
    3502
    3503 	var pubKey = sc.validateCertificateChain(crypto);
    3504 	sc.openSecureChannel(crypto, pubKey);
    3505
    3506 	sc.verifyUserPIN(sci.userPIN);
    3507
    3508 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, 1024);
    3509 	sc.generateAsymmetricKeyPair(1, 0, kg.encode());
    3510
    3511 	var dp = new Key();
    3512 	dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
    3513
    3514 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, dp);
    3515 	sc.generateAsymmetricKeyPair(2, 0, kg.encode());
    3516
    3517 	var list = sc.enumerateKeys();
    3518 	GPSystem.log(GPSystem.DEBUG, module.id, "Keys on device: " + list);
    3519
    3520 	var crypto = sc.getCrypto();
    3521 	var message = new ByteString("Hello World", ASCII);
    3522
    3523 	var key = sc.getKey(1);
    3524 	var signature = crypto.sign(key, Crypto.RSA_SHA256, message);
    3525 	GPSystem.log(GPSystem.DEBUG, module.id, "Signature: " + signature);
    3526
    3527 	var key = sc.getKey(2);
    3528 	var signature = crypto.sign(key, Crypto.ECDSA, message);
    3529 	GPSystem.log(GPSystem.DEBUG, module.id, "Signature: " + signature);
    3530 }
    3531