      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 	this.ks.storeEndEntityCertificate(label, req);
    157
    158 	var puk = req.getPublicKey();
    159 	var prk = this.ks.getKey(label);
    160 	return { prk: prk, puk: puk, req: req.getBytes() };
    161 }
    162
    163
    164
    165 /**
    166  * Delete private key
    167  *
    168  * @param {String} label the key label
    169  */
    170 CryptoProvider.prototype.deletePrivateKey = function(label) {
    171 	this.ks.deleteKey(label);
    172 }
    173
    174
    175
    176 /**
    177  * Generate a symmetric key under the given label
    178  *
    179  * @param {String} label the label for this key
    180  * @param {Number} keySize either 128, 192 or 256
    181  * @param {ByteString} allowedAlgorithms the optional list of allowed algorithms (0x10 for encryption, 0x11 for decryption, 0x18 for CMAC). By default all algorithms are allowed.
    182  * @param {String} wrappingKeyLabel the label of the optional wrapping key
    183  * @return the new key wrapped with the wrapping key
    184  * @type ByteString
    185  */
    186 CryptoProvider.prototype.generateKey = function(label, keySize, allowedAlgorithms, wrappingKeyLabel) {
    187 	GPSystem.log(GPSystem.DEBUG, module.id, "generateKey(" + label + ", " + keySize + ")");
    188
    189 	if (this.ks.hasKey(label)) {
    190 		if (this.deleteIfExists) {
    191 			this.ks.deleteKey(label);
    192 		} else {
    193 			throw new GPError(module.id, GPError.INVALID_DATA, 0, "A key with label " + label + " does already exist");
    194 		}
    195 	}
    196
    197 	if (!allowedAlgorithms) {
    198 		var allowedAlgorithms = new ByteString("101118", HEX);
    199 	}
    200
    201 	var kg = new SmartCardHSMKeySpecGenerator(Crypto.AES, keySize);
    202 	kg.setAlgorithms(allowedAlgorithms);
    203
    204 	if (wrappingKeyLabel) {
    205 		if (!this.ks.hasKey(wrappingKeyLabel)) {
    206 			throw new GPError(module.id, GPError.INVALID_DATA, 0, "A key with label " + wrappingKeyLabel + " does already exist");
    207 		}
    208 		var wrappingKey = this.ks.getKey(wrappingKeyLabel);
    209 		kg.wrappingKey = wrappingKey.getId();
    210 	}
    211
    212 	if (this.slot >= 0) {
    213 		GPSystem.log(GPSystem.DEBUG, module.id, "set key domain to " + this.slot);
    214 		kg.setKeyDomain(this.slot);
    215 	}
    216
    217 	var wrapbin = this.ks.generateKey(label, kg);
    218 	return wrapbin;
    219 }
    220