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