Skip to content

Commit

Permalink
FAB-10916 NodeSDK - allow create peers without TLS
Browse files Browse the repository at this point in the history
The addition of Discovery has required a client cert/key pair
when remotes enpoints are created.  When not provided a self
cert key pair will be created based off the current user.
V1.0 allowed remote endpoints to be created before assigning
a user to the client and/or assigning a client cert/key pair.
This change will not require the assigning of cert/key or user
for remote endpoints to be created.

Change-Id: I6ba5d3f5550071d18919e1c358e00bf083839c50
Signed-off-by: Bret Harrison <[email protected]>
  • Loading branch information
harrisob authored and Dave Kelsey committed Jun 28, 2018
1 parent 8bb7f22 commit 6607f7f
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 26 deletions.
2 changes: 1 addition & 1 deletion fabric-client/lib/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ const Channel = class {

const authentication = new _discoveryProto.AuthInfo();
authentication.setClientIdentity(signer.serialize());
const cert_hash = this._clientContext.getClientCertHash();
const cert_hash = this._clientContext.getClientCertHash(true);
if (cert_hash) {
authentication.setClientTlsCertHash(cert_hash);
}
Expand Down
42 changes: 25 additions & 17 deletions fabric-client/lib/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const Client = class extends BaseClient {

// When using a network configuration (connection profile) the client
// side mutual tls cert and key must be stored here
// -- also store the hash after computing
this._tls_mutual = {};

this._organizations = new Map();
Expand Down Expand Up @@ -150,32 +151,31 @@ const Client = class extends BaseClient {
logger.debug('setTlsClientCertAndKey - start');
this._tls_mutual.clientCert = clientCert;
this._tls_mutual.clientKey = clientKey;
this._tls_mutual.clientCertHash = null;
}

/**
* Utility method to add the mutual tls client material to a set of options.
* If the tls client material has not been set for the client, it will be generated.
* If the tls client material has not been set for the client, it will be
* generated if the user and crypto suite has been assigned to this client.
* @param {object} opts - The options object holding the connection settings
* that will be updated with the mutual TLS clientCert and clientKey.
* @throws Will throw an error if generating the tls client material fails
*/
addTlsClientCertAndKey(opts) {
if (!this._tls_mutual.clientCert || !this._tls_mutual.clientKey) {
if (this._cryptoSuite && this._userContext) {
logger.debug('addTlsClientCertAndKey - generating self-signed TLS client certificate');
// generate X509 cert pair
let key = this._cryptoSuite.generateEphemeralKey();
this._tls_mutual.clientKey = key.toBytes();
this._tls_mutual.clientCert = key.generateX509Certificate(this._userContext.getName());
}
}
// use client cert pair if it exists
if (this._tls_mutual.clientCert && this._tls_mutual.clientKey) {
opts.clientCert = this._tls_mutual.clientCert;
opts.clientKey = this._tls_mutual.clientKey;
} else {
if (!this._cryptoSuite) {
throw new Error('A crypto suite has not been assigned to this client');
}
if (!this._userContext) {
throw new Error('A user context has not been assigned to this client');
}
logger.debug('addTlsClientCertAndKey - generating self-signed TLS client certificate');
// generate X509 cert pair
let key = this._cryptoSuite.generateEphemeralKey();
opts.clientKey = key.toBytes();
opts.clientCert = key.generateX509Certificate(this._userContext.getName());
}
}

Expand Down Expand Up @@ -1776,22 +1776,30 @@ const Client = class extends BaseClient {

/**
* Get the client certificate hash
* @param {boolean} create - Optional. Create the hash based on the current
* user if the cleint cert has not been assigned to this client
* @returns {byte[]} The hash of the client certificate
*/
getClientCertHash() {
getClientCertHash(create) {
const method = 'getClientCertHash';
logger.debug('%s - start', method);
if(this._tls_mutual.clientCertHash) {
return this._tls_mutual.clientCertHash;
}
if(!this._tls_mutual.clientCert && create) {
// this will create the cert and key from the current user if available
this.addTlsClientCertAndKey({});
}

let hash = null;
if (this._tls_mutual.clientCert) {
logger.debug('%s - using clientCert %s', method, this._tls_mutual.clientCert);
let der_cert = sdkUtils.pemToDER(this._tls_mutual.clientCert);
hash = computeHash(der_cert);
this._tls_mutual.clientCertHash = computeHash(der_cert);
} else {
logger.debug('%s - no tls client cert', method);
}

return hash;
return this._tls_mutual.clientCertHash;
}

_checkTLScert_n_key(opts) {
Expand Down
8 changes: 4 additions & 4 deletions test/integration/e2e/e2eUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ function instantiateChaincodeWithId(userOrg, chaincode_id, chaincode_path, versi

// this is the longest response delay in the test, sometimes
// x86 CI times out. set the per-request timeout to a super-long value
return channel.sendUpgradeProposal(request, 5*60*1000)
return channel.sendUpgradeProposal(request, 10*60*1000)
.then((results) => {
let proposalResponses = results[0];

Expand All @@ -303,7 +303,7 @@ function instantiateChaincodeWithId(userOrg, chaincode_id, chaincode_path, versi
version, language, upgrade, transientMap);
tx_id = request.txId;

return channel.sendUpgradeProposal(request, 5*60*1000);
return channel.sendUpgradeProposal(request, 10*60*1000);
} else {
throw new Error('Failed to test for bad transient map. The chaincode should have rejected the upgrade proposal.');
}
Expand All @@ -318,9 +318,9 @@ function instantiateChaincodeWithId(userOrg, chaincode_id, chaincode_path, versi
// this is the longest response delay in the test, sometimes
// x86 CI times out. set the per-request timeout to a super-long value
if(upgrade) {
return channel.sendUpgradeProposal(request, 5*60*1000);
return channel.sendUpgradeProposal(request, 10*60*1000);
} else {
return channel.sendInstantiateProposal(request, 5*60*1000);
return channel.sendInstantiateProposal(request, 10*60*1000);
}
}

Expand Down
18 changes: 14 additions & 4 deletions test/unit/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -1033,27 +1033,36 @@ test('\n\n*** Test normalizeX509 ***\n', function(t) {

test('\n\n*** Test Add TLS ClientCert ***\n', function (t) {
var testClient = new Client();
t.throws(
t.doesNotThrow(
() => {
testClient.addTlsClientCertAndKey({});
},
/A crypto suite has not been assigned to this client/,
'Check that error is thrown when crypto suite is not set'
'Check that error is not thrown when crypto suite is not set'
);
testClient.setCryptoSuite(Client.newCryptoSuite());
t.throws(
t.doesNotThrow(
() => {
testClient.addTlsClientCertAndKey({});
},
/A user context has not been assigned to this client/,
'Check that error is thrown when user context is not set'
'Check that error is not thrown when user context is not set'
);
testClient.setUserContext(new User('testUser'), true);
try {
t.notOk(testClient._tls_mutual.clientKey, 'Check that client key is not there');
t.notOk(testClient._tls_mutual.clientCert, 'Check that client certain is not there');
t.notOk(testClient._tls_mutual.clientCertHash, 'Check that cert hash was not cached');

t.ok(testClient.getClientCertHash(true), 'Check forcing the hash to be based off the user');
t.ok(testClient._tls_mutual.clientCertHash, 'Check that cert hash was cached');

const tls_cert_key = {};
testClient.addTlsClientCertAndKey(tls_cert_key);
t.ok(tls_cert_key.clientCert, 'Check that clientCert exists');
t.ok(tls_cert_key.clientKey, 'Check that clientKey exists');
t.ok(testClient._tls_mutual.clientKey, 'Check that client key is there');
t.ok(testClient._tls_mutual.clientCert, 'Check that client cert is there');
} catch (err) {
t.fail('addTlsClientCertandKey failed: ' + err);
}
Expand All @@ -1063,6 +1072,7 @@ test('\n\n*** Test Add TLS ClientCert ***\n', function (t) {

test('\n\n*** Test Set and Add TLS ClientCert ***\n', function(t) {
let client = new Client();
t.notOk(client.getClientCertHash(), 'Check getting null hash when no client cert assigned');
client.setTlsClientCertAndKey(aPem, aPem);
t.pass('Able to set the client cert and client key');
const tls_cert_key = {};
Expand Down

0 comments on commit 6607f7f

Please sign in to comment.