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