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