1 /** 2 * --------- 3 * |.##> <##.| SmartCard-HSM Support Scripts 4 * |# #| 5 * |# #| Copyright (c) 2011-2016 CardContact Systems GmbH 6 * |'##> <##'| Schuelerweg 38, 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 Crypto Provider 25 */ 26 27 var SmartCardHSM = require('scsh/sc-hsm/SmartCardHSM').SmartCardHSM; 28 var SmartCardHSMKeySpecGenerator = require('scsh/sc-hsm/SmartCardHSM').SmartCardHSMKeySpecGenerator; 29 var SmartCardHSMSymmetricKeySpecGenerator = require('scsh/sc-hsm/SmartCardHSM').SmartCardHSMSymmetricKeySpecGenerator; 30 var HSMKeyStore = require('scsh/sc-hsm/HSMKeyStore').HSMKeyStore; 31 32 33 34 /** 35 * Crypto Provider for accessing a SmartCard-HSM 36 * 37 * @param {SmartCardHSM} sc the associated SmartCard-HSM 38 * @param {Number} slot the key domain slot. If undefined or -1 no key domain will be set 39 */ 40 function CryptoProvider(sc, id, slot) { 41 this.id = id; 42 this.slot = slot; // the key domain slot 43 this.setSmartCardHSM(sc); 44 this.deleteIfExists = false; 45 } 46 47 exports.CryptoProvider = CryptoProvider; 48 49 50 51 /** 52 * Replace SmartCard-HSM 53 * 54 * @param {SmartCardHSM} sc the new SmartCard-HSM 55 */ 56 CryptoProvider.prototype.setSmartCardHSM = function(sc) { 57 this.sc = sc; 58 this.ks = new HSMKeyStore(sc); 59 } 60 61 62 63 /** 64 * Release this crypto provider 65 * 66 * The release() method shall be called if the provider is not used anymore 67 * Place the release in the finally statement of a try/catch block 68 */ 69 CryptoProvider.prototype.release = function() { 70 } 71 72 73 74 /** 75 * Get crypto object 76 * 77 * This method is part of the API. 78 * 79 * @type HSMCrypto 80 * @return the HSMCrypto object 81 */ 82 CryptoProvider.prototype.getCrypto = function() { 83 if (this.sc) { 84 return this.sc.getCrypto(); 85 } 86 return new Crypto(); 87 } 88 89 90 91 /** 92 * Get a handle for a private key stored on the SmartCard-HSM 93 * 94 * @param {String} label the label of the private key 95 * @param {ByteString} blob the optional key blob 96 * @returns the private key 97 * @type Key 98 */ 99 CryptoProvider.prototype.getPrivateKeyByLabel = function(label, blob) { 100 GPSystem.log(GPSystem.DEBUG, module.id, "getPrivateKeyByLabel(" + label + ")"); 101 var key = this.ks.getKey(label); 102 GPSystem.log(GPSystem.DEBUG, module.id, "key " + key); 103 return key; 104 } 105 106 107 108 /** 109 * Get a handle for a private key stored on the SmartCard-HSM 110 * 111 * @param {String} label the label of the private key 112 * @param {ByteString} blob the optional key blob 113 * @returns the private key 114 * @type Key 115 */ 116 CryptoProvider.prototype.getPrivateKeyByKeyId = function(keyid, blob) { 117 GPSystem.log(GPSystem.DEBUG, module.id, "getPrivateKeyByKeyId(" + keyid + ")"); 118 var key = this.ks.getKey(keyid); 119 GPSystem.log(GPSystem.DEBUG, module.id, "key " + key); 120 return key; 121 } 122 123 124 125 /** 126 * Generate a key pair under the given label with the key characteristics defined in keyspec 127 * 128 * @param {String} label the label for this key 129 * @param {Key} the key specification 130 * @return an object containing the private key as property prk and the public key as property puk 131 * @type Object 132 */ 133 CryptoProvider.prototype.generateKeyPair = function(label, keyspec) { 134 GPSystem.log(GPSystem.DEBUG, module.id, "generateKeyPair(" + label + ")"); 135 136 if (this.ks.hasKey(label)) { 137 if (this.deleteIfExists) { 138 this.ks.deleteKey(label); 139 } else { 140 throw new GPError(module.id, GPError.INVALID_DATA, 0, "A key with label " + label + " does already exist"); 141 } 142 } 143 144 if (typeof(keyspec.getComponent(Key.ECC_P)) != "undefined") { 145 var kg = new SmartCardHSMKeySpecGenerator(Crypto.EC, keyspec); 146 } else { 147 var kg = new SmartCardHSMKeySpecGenerator(Crypto.RSA, keyspec.getSize()); 148 } 149 150 if (this.slot >= 0) { 151 GPSystem.log(GPSystem.DEBUG, module.id, "set key domain to " + this.slot); 152 kg.setKeyDomain(this.slot); 153 } 154 155 var req = this.ks.generateKeyPair(label, kg); 156 var puk = req.getPublicKey(); 157 var prk = this.ks.getKey(label); 158 return { prk: prk, puk: puk, req: req.getBytes() }; 159 } 160 161 162 163 /** 164 * Delete private key 165 * 166 * @param {String} label the key label 167 */ 168 CryptoProvider.prototype.deletePrivateKey = function(label) { 169 this.ks.deleteKey(label); 170 } 171 172 173 174 /** 175 * Generate a symmetric key under the given label 176 * 177 * @param {String} label the label for this key 178 * @param {Number} keySize either 128, 192 or 256 179 * @param {ByteString} allowedAlgorithms the optional list of allowed algorithms (0x10 for encryption, 0x11 for decryption, 0x18 for CMAC). By default all algorithms are allowed. 180 * @param {String} wrappingKeyLabel the label of the optional wrapping key 181 * @return the new key wrapped with the wrapping key 182 * @type ByteString 183 */ 184 CryptoProvider.prototype.generateKey = function(label, keySize, allowedAlgorithms, wrappingKeyLabel) { 185 GPSystem.log(GPSystem.DEBUG, module.id, "generateKey(" + label + ", " + keySize + ")"); 186 187 if (this.ks.hasKey(label)) { 188 if (this.deleteIfExists) { 189 this.ks.deleteKey(label); 190 } else { 191 throw new GPError(module.id, GPError.INVALID_DATA, 0, "A key with label " + label + " does already exist"); 192 } 193 } 194 195 if (!allowedAlgorithms) { 196 var allowedAlgorithms = new ByteString("101118", HEX); 197 } 198 199 var kg = new SmartCardHSMKeySpecGenerator(Crypto.AES, keySize); 200 kg.setAlgorithms(allowedAlgorithms); 201 202 if (wrappingKeyLabel) { 203 if (!this.ks.hasKey(wrappingKeyLabel)) { 204 throw new GPError(module.id, GPError.INVALID_DATA, 0, "A key with label " + wrappingKeyLabel + " does already exist"); 205 } 206 var wrappingKey = this.ks.getKey(wrappingKeyLabel); 207 kg.wrappingKey = wrappingKey.getId(); 208 } 209 210 if (this.slot >= 0) { 211 GPSystem.log(GPSystem.DEBUG, module.id, "set key domain to " + this.slot); 212 kg.setKeyDomain(this.slot); 213 } 214 215 var wrapbin = this.ks.generateKey(label, kg); 216 return wrapbin; 217 } 218