      1 /**
      2  *  ---------
      3  * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
      4  * |#       #|
      5  * |#       #|  Copyright (c) 1999-2009 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 A card verifiable certificate store using a SmartCard-HSM as key store
     25  */
     26
     27 // Imports
     28
     29 var PublicKeyReference	 = require('scsh/eac/PublicKeyReference').PublicKeyReference;
     30 var CVC					 = require('scsh/eac/CVC').CVC;
     31 var CVCertificateStore	 = require('scsh/eac/CVCertificateStore').CVCertificateStore;
     32 var SmartCardHSM		 = require('scsh/sc-hsm/SmartCardHSM').SmartCardHSM;
     33 var SmartCardHSMKey		 = require('scsh/sc-hsm/SmartCardHSM').SmartCardHSMKey;
     34 var CVCCA				 = require('scsh/eac/CVCCA').CVCCA;
     35
     36
     37
     38 /**
     39  * Create a CV certificate store using a SmartCard-HSM as secure key store
     40  *
     41  * @class CV certificate store with SmartCard-HSM as secure key store
     42  * @constructor
     43  * @param {DAOFactory} daof the factory that can create data access objects for persistent information
     44  * @param {SmartCardHSM} sc the SmartCard-HSM access object
     45  */
     46 function HSMCVCertificateStore(daof, sc) {
     47 	CVCertificateStore.call(this, daof);
     48 	if (sc) {
     49 		this.sc = sc;
     50 		sc.enumerateKeys();
     51 	}
     52 }
     53
     54 HSMCVCertificateStore.prototype = Object.create(CVCertificateStore.prototype);
     55 HSMCVCertificateStore.constructor = HSMCVCertificateStore;
     56
     57 exports.HSMCVCertificateStore = HSMCVCertificateStore;
     58
     59
     60
     61 HSMCVCertificateStore.prototype.setSmartCardHSM = function(sc) {
     62 	this.sc = sc;
     63 	sc.enumerateKeys();
     64 }
     65
     66
     67
     68 /**
     69  * Get crypto object
     70  *
     71  * @type HSMCrypto
     72  * @return the HSMCrypto object
     73  */
     74 HSMCVCertificateStore.prototype.getCrypto = function() {
     75 	if (this.sc) {
     76 		return this.sc.getCrypto();
     77 	}
     78 	return new Crypto();
     79 }
     80
     81
     82
     83 /**
     84  * Transform path and certificate holder into a label
     85  *
     86  * @param {String} path the path
     87  * @param {PublicKeyReference} chr the certificate holder reference
     88  * @type String
     89  * @return the key label
     90  */
     91 HSMCVCertificateStore.path2label = function(path, chr) {
     92 	return path.substr(1) + chr.getSequenceNo();
     93 }
     94
     95
     96
     97 /**
     98  * Get a private key in the certificate store. Overrides method in CVCertificateStore.
     99  *
    100  * @param {String} path the relative path of the PKI element (e.g. "/UTCVCA1/UTDVCA1/UTTERM")
    101  * @param {PublicKeyReference} chr the public key reference for this key
    102  * @returns the private key or null if not found
    103  * @type Key
    104  */
    105 HSMCVCertificateStore.prototype.getPrivateKey = function(path, car) {
    106 	var label = HSMCVCertificateStore.path2label(path, car);
    107 	print("Get private key " + label);
    108
    109 	return this.sc.getKey(label);
    110 }
    111
    112
    113
    114 /**
    115  * Generate a certificate request using a private key in the SmartCard-HSM
    116  *
    117  * @param {String} path the relative path of the PKI element (e.g. "/UTCVCA1/UTDVCA1")
    118  * @param {PublicKeyReference} car the CA at which this request is addressed
    119  * @param {boolean} forceInitial force an initial request, even if a current certificate is available
    120  * @param {boolean} signinitial sign with initial key (sequence = 00000)
    121  * @param {Key} keyspec a key object containing key parameters (e.g. EC Curve)
    122  * @param {ByteString} algo the terminal authentication algorithm object identifier
    123  * @return the certificate request
    124  * @type CVC
    125  */
    126 HSMCVCertificateStore.prototype.generateRequest = function(path, car, forceinitial, signinitial, keyspec, algo, countryseq) {
    127
    128 	// Determine CHR
    129 	var currentchr = this.getCurrentCHR(path);
    130 	var nextchr = this.getNextCHR(path, countryseq);
    131 	var label = HSMCVCertificateStore.path2label(path, nextchr);
    132
    133 	if (car == null) {			// CAR is not optional in SmartCard-HSM generated requests
    134 		car = nextchr;			// Use the CHR if no CAR defined.
    135 	}
    136
    137 	var signkid = 0;
    138 	if ((currentchr != null) && !forceinitial) {
    139 		var curlabel = HSMCVCertificateStore.path2label(path, currentchr);
    140 		var key = this.sc.getKey(curlabel);
    141 		if (key == null) {
    142 			throw new GPError("HSMCVCertificateStore", GPError.DEVICE_ERROR, 0, "Key " + curlabel + " not found");
    143 		}
    144 		var signkid = key.getId();
    145 		var outerCAR = currentchr;
    146 	}
    147
    148 	var key = this.sc.getKey(label);
    149 	if (key) {
    150 		var newkid = key.getId();
    151 	} else {
    152 		var newkid = this.sc.determineFreeKeyId();
    153 	}
    154
    155 	if (typeof(keyspec.getComponent(Key.ECC_P)) != "undefined") {
    156 		var keysize = keyspec.getSize();
    157 		print("1:Keysize " + keysize);
    158 		if (keysize < 0) {
    159 			var keysize = keyspec.getComponent(Key.ECC_P).length << 3;
    160 			print("2:Keysize " + keysize);
    161 		}
    162 		var keydata = SmartCardHSM.buildGAKPwithECC(car, algo, nextchr, keyspec, outerCAR);
    163 		var keydesc = SmartCardHSM.buildPrkDforECC(newkid, label, keysize);
    164 	} else {
    165 		var keydata = SmartCardHSM.buildGAKPwithRSA(car, algo, nextchr, keyspec.getSize(), outerCAR);
    166 		var keydesc = SmartCardHSM.buildPrkDforRSA(newkid, label, keyspec.getSize());
    167 	}
    168
    169 	var reqbin = this.sc.generateAsymmetricKeyPair(newkid, signkid, keydata);
    170
    171 	var fid = ByteString.valueOf((SmartCardHSM.PRKDPREFIX << 8) + newkid);
    172 	this.sc.updateBinary(fid, 0, keydesc.getBytes());
    173
    174 	if (((currentchr == null) || forceinitial) && !signinitial) {
    175 		var a = new ASN1(reqbin);
    176 		a = a.get(0);
    177 		var req = new CVC(a.getBytes());
    178 	} else {
    179 		var req = new CVC(reqbin);
    180 	}
    181
    182 	var hkey = new SmartCardHSMKey(this.sc, newkid);
    183 	hkey.setDescription(keydesc);
    184 	this.sc.addKeyToMap(hkey);
    185
    186 	return req;
    187 }
    188
    189
    190
    191 /**
    192  * Get a private key in the certificate store. Overrides method in CVCertificateStore.
    193  *
    194  * @param {String} path the relative path of the PKI element (e.g. "/UTCVCA1/UTDVCA1/UTTERM")
    195  * @param {PublicKeyReference} chr the public key reference for this key
    196  * @returns the private key or null if not found
    197  * @type Key
    198  */
    199 HSMCVCertificateStore.prototype.deletePrivateKey = function(path, car) {
    200 	var label = HSMCVCertificateStore.path2label(path, car);
    201 	print("Get private key " + label);
    202
    203 	return this.sc.getKey(label);
    204 }
    205
    206
    207
    208 HSMCVCertificateStore.testPath = GPSystem.mapFilename("testca", GPSystem.CWD);
    209
    210 HSMCVCertificateStore.test = function() {
    211 	var card = new Card(_scsh3.reader);
    212
    213 	var sc = new SmartCardHSM(card);
    214 	sc.verifyUserPIN(new ByteString("648219", ASCII));
    215 	var cs = new HSMCVCertificateStore(HSMCVCertificateStore.testPath + "/cvca", sc);
    216
    217 	var crypto = sc.getCrypto();
    218
    219 	var cvca = new CVCCA(crypto, cs, null, null, "/UTCVCA");
    220
    221 	// Create a new request
    222 	var car = new PublicKeyReference("UTCVCA00000");
    223
    224 	var req = cvca.generateRequest(car, false);
    225 	print("Request: " + req);
    226 	print(req.getASN1());
    227
    228 	assert(req.verifyWith(crypto, req.getPublicKey()));
    229
    230 	// Create self-signed or link certificate based on request
    231 	var policy = { certificateValidityDays: 2,
    232 				   chatRoleOID: new ByteString("id-IS", OID),
    233 				   chatRights: new ByteString("E3", HEX),
    234 				   includeDomainParameter: true,
    235 				   extensions: []
    236 				 };
    237 	var cert = cvca.generateCertificate(req, policy);
    238 	print("Certificate: " + cert);
    239 	print(cert.getASN1());
    240
    241 	// Import certificate into store, making it the most current certificate
    242 	cvca.storeCertificate(cert);
    243
    244 	// Generate additional self-signed root certificate
    245 	// This must be done after the link certificate has been imported
    246 	var policy = { certificateValidityDays: 2,
    247 				   chatRoleOID: new ByteString("id-IS", OID),
    248 				   chatRights: new ByteString("E3", HEX),
    249 				   includeDomainParameter: true,
    250 				   extensions: []
    251 				 };
    252 	var cert = cvca.generateCertificate(req, policy);
    253 	print("Certificate: " + cert);
    254 	print(cert.getASN1());
    255
    256 	// Import certificate into store, making it the most current certificate
    257 	cvca.storeCertificate(cert);
    258 }
    259