Skip to content

Commit

Permalink
Fix fabric-ca-client tests
Browse files Browse the repository at this point in the history
FAB-2431
Some fabric-ca client related tests need to be fixed due to
changes in CryptoSuite impl and utils.getCryptoSuite() API

Change-Id: I6e7ef27445073ad272beefafcfff2ad6dbebc31c
Signed-off-by: Jim Zhang <jzhang@us.ibm.com>
  • Loading branch information
jimthematrix committed Feb 22, 2017
1 parent c34c643 commit 2ba668c
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 45 deletions.
4 changes: 2 additions & 2 deletions fabric-ca-client/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"crypto-keysize": 256,
"crypto-hsm": false,
"crypto-suite-software": {
"EC": "./impl/CryptoSuite_ECDSA_AES.js"
"EC": "fabric-ca-client/lib/impl/CryptoSuite_ECDSA_AES.js"
},
"crypto-suite-hsm": {
"EC": "./impl/bccsp_pkcs11.js"
"EC": "fabric-ca-client/lib/impl/bccsp_pkcs11.js"
},
"key-value-store": "fabric-ca-client/lib/impl/FileKeyValueStore.js"
}
16 changes: 13 additions & 3 deletions fabric-ca-client/lib/FabricCAClientImpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,19 @@ var FabricCAServices = class {
* constructor
*
* @param {string} url The endpoint URL for Fabric CA services of the form: "http://host:port" or "https://host:port"
* @param {KeyValueStore} kvs KeyValueStore for CryptoSuite
* @param {object} cryptoSetting This optional parameter is an object with the following optional properties:
* - software {boolean}: Whether to load a software-based implementation (true) or HSM implementation (false)
* default is true (for software based implementation), specific implementation module is specified
* in the setting 'crypto-suite-software'
* - keysize {number}: The key size to use for the crypto suite instance. default is value of the setting 'crypto-keysize'
* - algorithm {string}: Digital signature algorithm, currently supporting ECDSA only with value "EC"
*
* @param {string} KVSImplClass Optional. The built-in key store saves private keys. The key store may be backed by different
* {@link KeyValueStore} implementations. If specified, the value of the argument must point to a module implementing the
* KeyValueStore interface.
* @param {object} opts Implementation-specific options object for the {@link KeyValueStore} class to instantiate an instance
*/
constructor(url, kvs) {
constructor(url, cryptoSettings, KVSImplClass, opts) {

var endpoint = FabricCAServices._parseURL(url);

Expand All @@ -51,7 +61,7 @@ var FabricCAServices = class {
port: endpoint.port
});

this.cryptoPrimitives = utils.getCryptoSuite(kvs);
this.cryptoPrimitives = utils.getCryptoSuite(cryptoSettings, KVSImplClass, opts);

logger.info('Successfully constructed Fabric CA service client: endpoint - %j', endpoint);

Expand Down
4 changes: 2 additions & 2 deletions fabric-client/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"crypto-keysize": 256,
"crypto-hsm": false,
"crypto-suite-software": {
"EC": "./impl/CryptoSuite_ECDSA_AES.js"
"EC": "fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js"
},
"crypto-suite-hsm": {
"EC": "./impl/bccsp_pkcs11.js"
"EC": "fabric-client/lib/impl/bccsp_pkcs11.js"
},
"key-value-store": "fabric-client/lib/impl/FileKeyValueStore.js",
"nonce-size" : 24
Expand Down
30 changes: 16 additions & 14 deletions fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,35 +49,37 @@ var CryptoSuite_ECDSA_AES = class extends api.CryptoSuite {
* constructor
*
* @param {number} keySize Key size for the ECDSA algorithm, can only be 256 or 384
* @param {object} opts Implementation-specific options object for the {@link KeyValueStore} class to instantiate an instance
* @param {string} KVSImplClass Optional. The built-in key store saves private keys. The key store may be backed by different
* {@link KeyValueStore} implementations. If specified, the value of the argument must point to a module implementing the
* KeyValueStore interface.
* @param {object} opts Implementation-specific options object for the {@link KeyValueStore} class to instantiate an instance
*/
constructor(keySize, KVSImplClass, opts) {
constructor(keySize, opts, KVSImplClass) {
if (keySize !== 256 && keySize !== 384) {
throw new Error('Illegal key size: ' + keySize + ' - this crypto suite only supports key sizes 256 or 384');
}

super();

var superClass;

if (typeof KVSImplClass !== 'function') {
superClass = require(utils.getConfigSetting('key-value-store'));
} else {
superClass = KVSImplClass;
}

if (KVSImplClass && typeof opts === 'undefined') {
// the function is called with only one argument for the 'opts'
opts = KVSImplClass;
} else if (typeof KVSImplClass === 'undefined' && typeof opts === 'undefined') {
if (typeof opts === 'undefined' || opts === null) {
opts = {
path: CryptoSuite_ECDSA_AES.getDefaultKeyStorePath()
};
}

var superClass;

if (typeof KVSImplClass !== 'undefined' && KVSImplClass !== null) {
if (typeof KVSImplClass !== 'function') {
throw new Error('Super class for the key store must be a module.');
} else {
superClass = KVSImplClass;
}
} else {
// no super class specified, use the default key value store implementation
superClass = require(utils.getConfigSetting('key-value-store'));
}

this._keySize = keySize;
this._store = null;
this._storeConfig = {
Expand Down
50 changes: 39 additions & 11 deletions fabric-client/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,25 @@ var sha3_256 = require('js-sha3').sha3_256;
// - keysize {number}: The key size to use for the crypto suite instance. default is value of the setting 'crypto-keysize'
// - algorithm {string}: Digital signature algorithm, currently supporting ECDSA only with value "EC"
//
// @param {function} KVSImplClass Optional. The built-in key store saves private keys. The key store may be backed by different
// {@link KeyValueStore} implementations. If specified, the value of the argument must point to a module implementing the
// KeyValueStore interface.
// @param {object} opts Implementation-specific option object used in the constructor
//
module.exports.getCryptoSuite = function(setting, opts) {
module.exports.getCryptoSuite = function(setting, KVSImplClass, opts) {
var csImpl, keysize, algorithm, haveSettings = false;

csImpl = this.getConfigSetting('crypto-hsm') ? this.getConfigSetting('crypto-suite-hsm') : this.getConfigSetting('crypto-suite-software');

// this function supports skipping any of the arguments such that it can be called in any of the following fashions:
// - getCryptoSuite({software: true, keysize: 256, algorithm: EC}, CouchDBKeyValueStore, {name: 'member_db', url: 'http://localhost:5984'})
// - getCryptoSuite(CouchDBKeyValueStore, {name: 'member_db', url: 'http://localhost:5984'})
// - getCryptoSuite({software: true, keysize: 256, algorithm: EC}, {path: '/tmp/app-state-store'})
// - getCryptoSuite({software: false}, {lib: '/usr/local/bin/pkcs11.so', slot: 0, pin: '1234'})
// - getCryptoSuite({keysize: 384})
// - getCryptoSuite()

// step 1: what's the cryptosuite impl to use, key size and algo
if (typeof setting === 'object' && typeof setting.keysize === 'number') {
keysize = setting.keysize;
haveSettings = true;
Expand All @@ -74,19 +86,35 @@ module.exports.getCryptoSuite = function(setting, opts) {
// expecting a path to an alternative implementation
var cryptoSuite = require(csImpl);

if (typeof setting !== 'undefined' && typeof opts !== 'undefined')
return new cryptoSuite(keysize, opts);
// step 2: what's the super class to use for the crypto key store?
var keystoreSuperClass;

if (typeof KVSImplClass === 'function') {
keystoreSuperClass = KVSImplClass;
} else {
keystoreSuperClass = null;
}

if (typeof setting !== 'undefined') {
// only one object is passed in as argument, we need to decide whether it's meant for the 'setting' or 'opts'
if (haveSettings)
return new cryptoSuite(keysize); // this implementation must not need any opts because no 'opts' argument was passed in
else
return new cryptoSuite(keysize, setting); // the function was called with only the 'opts' argument
// step 3: what 'opts' object should be passed to the cryptosuite impl?
if (KVSImplClass && typeof opts === 'undefined') {
if (typeof KVSImplClass === 'function') {
// the super class module was passed in, but not the 'opts'
opts = null;
} else {
// called with only one argument for the 'opts' but KVSImplClass was skipped
opts = KVSImplClass;
}
} else if (typeof KVSImplClass === 'undefined' && typeof opts === 'undefined') {
if (haveSettings) {
// the function was called with only the 'settings' argument
opts = null;
} else {
// the function was called with only the 'opts' argument or none at all
opts = (typeof setting === 'undefined') ? null : setting;
}
}

// the function was called without any argument
return new cryptoSuite(keysize);
return new cryptoSuite(keysize, opts, keystoreSuperClass);
};

// Provide a Promise-based keyValueStore for couchdb, etc.
Expand Down
19 changes: 11 additions & 8 deletions test/integration/cloudant-fabricca-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,25 @@ var hfc = require('fabric-client');
var Client = hfc;
var User = require('fabric-client/lib/User.js');
var FabricCAServices = require('fabric-ca-client/lib/FabricCAClientImpl');
var CouchDBKeyValueStore = require('fabric-client/lib/impl/CouchDBKeyValueStore');

var utils = require('fabric-client/lib/utils.js');
var couchdbUtil = require('./couchdb-util.js');

// Use the Cloudant specific config file
require('../unit/util.js').resetDefaults();

hfc.addConfigFile('test/fixtures/cloudant.json');
var dbClient = couchdbUtil.getCloudantClient();
var keyValueStore = hfc.getConfigSetting('key-value-store');
console.log('Key Value Store = ' + keyValueStore);

var cloudantUrl = 'https://1421acc7-6faa-491a-8e10-951e2e190684-bluemix:7179ef7a72602189243deeabe207889bde1c2fada173ae1022b5592e5a79dacc@1421acc7-6faa-491a-8e10-951e2e190684-bluemix.cloudant.com';

// This test first checks to see if a user has already been enrolled. If so,
// the test terminates. If the user is not yet enrolled, the test uses the
// FabricCAClientImpl to enroll a user, and saves the enrollment materials into the
// CouchDB KeyValueStore. Then the test uses the Chain class to load the member
// from the key value store.
test('Use FabricCAServices wih a Cloudant CouchDB KeyValueStore', function(t) {
t.equal(keyValueStore, 'fabric-client/lib/impl/CouchDBKeyValueStore.js', 'Check key value store override for CouchDBKeyValueStore');

//var user = new User();
var client = new Client();
Expand All @@ -49,11 +52,11 @@ test('Use FabricCAServices wih a Cloudant CouchDB KeyValueStore', function(t) {
var dbname = 'member_db';

var member;
couchdbUtil.destroy(dbname, dbClient)
couchdbUtil.destroy(dbname, cloudantUrl)
.then( function(status) {
t.comment('Cleanup of existing ' + dbname + ' returned '+status);
t.comment('Initilize the Cloudant CouchDB KeyValueStore');
utils.newKeyValueStore({name: dbname, path: dbClient})
utils.newKeyValueStore({name: dbname, url: cloudantUrl})
.then(
function(kvs) {
t.comment('Setting client keyValueStore to: ' + kvs);
Expand All @@ -66,7 +69,7 @@ test('Use FabricCAServices wih a Cloudant CouchDB KeyValueStore', function(t) {
process.exit(1);
}
t.comment('Initialize the CA server connection and KeyValueStore');
return new FabricCAServices('http://localhost:7054', kvs);
return new FabricCAServices('http://localhost:7054', {name: dbname, url: cloudantUrl});
},
function(err) {
console.log(err);
Expand All @@ -83,8 +86,8 @@ test('Use FabricCAServices wih a Cloudant CouchDB KeyValueStore', function(t) {
t.comment('Set cryptoSuite on client');
t.comment('Begin caService.enroll');
return caService.enroll({
enrollmentID: 'admin2',
enrollmentSecret: 'adminpw2'
enrollmentID: 'admin',
enrollmentSecret: 'adminpw'
});
},
function(err) {
Expand Down
2 changes: 1 addition & 1 deletion test/integration/endorser-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var testUtil = require('../unit/util.js');
var utils = require('fabric-client/lib/utils.js');

var keyValStorePath = testUtil.KVS;
var chaincode_id = 'end2end';
var chaincode_id = 'endorsertest';
var chaincode_version = 'endorser-v0';
var chain_id = 'testchainid';
var tx_id = null;
Expand Down
2 changes: 1 addition & 1 deletion test/integration/fabriccopservices-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var X509 = require('jsrsasign').X509;
var util = require('util');
var fs = require('fs');
var path = require('path');
var testUtil = require('./util.js');
var testUtil = require('../unit/util.js');
var utils = require('fabric-client/lib/utils.js');

var keyValStorePath = testUtil.KVS;
Expand Down
19 changes: 16 additions & 3 deletions test/unit/cryptosuite-ecdsa-aes.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,28 @@ test('\n\n** utils.getCryptoSuite tests **\n\n', (t) => {
cs._getKeyStore()
.then((store) => {
t.fail('Should not have been able to get a valid key store because of invalid store config');
t.end();
}).catch((err) => {
t.pass('Successfully rejected _getKeyStore() due to invalid config');
t.end();
});
},
null,
'Load the CryptoSuite_ECDSA_AES module and pass in an invalid config object'
);

cs = utils.getCryptoSuite({software: true, algorithm: 'EC', keysize: 256}, CouchDBKeyValueStore, { name: 'test_db', url: 'http://dummyUrl' });
cs._getKeyStore()
.then(() => {
t.fail('Should not have been able to get a valid key store because the url was invalid');
t.end();
}).catch((err) => {
if (err.message.indexOf('Error creating test_db database to store membership data: Error: getaddrinfo ENOTFOUND dummyurl') >= 0) {
t.pass('Successfully loaded CryptoKeyStore based on CouchDBKeyValueStore, but rejected _getKeyStore() because the url was invalid');
} else {
t.fail(err);
}

t.end();
});
});

test('\n\n ** CryptoSuite_ECDSA_AES - constructor tests **\n\n', function (t) {
Expand All @@ -194,7 +207,7 @@ test('\n\n ** CryptoSuite_ECDSA_AES - constructor tests **\n\n', function (t) {
var keyValueStore = null;
let cs;

cs = new CryptoSuite_ECDSA_AES(256, CouchDBKeyValueStore, { name: 'test_db', url: 'http://dummyUrl'});
cs = new CryptoSuite_ECDSA_AES(256, { name: 'test_db', url: 'http://dummyUrl'}, CouchDBKeyValueStore);
cs._getKeyStore()
.then(() => {
t.fail('Should not have been able to get a valid key store because the url was invalid');
Expand Down

0 comments on commit 2ba668c

Please sign in to comment.