Skip to content

Commit

Permalink
Add tls support to node SDK
Browse files Browse the repository at this point in the history
FAB-2722
The network set up is such that:
- signing keys and certs were from the cryptogen two-org
- tls keys and certs were taken from CR 7141 because the certs
  have special CN names to use in TLS

Now the entire test suite work fine, with all 495 tests passing

Note that fabric-ca-client still only supports http. It's being
worked on with FAB-1552.

Rebased on latest in master.

Change-Id: I2ea2b35f3a5b07fb10f88a16c0d35c4d3b097c0c
Signed-off-by: Jim Zhang <jzhang@us.ibm.com>
  • Loading branch information
jimthematrix committed Mar 14, 2017
1 parent 378f37c commit 3afcb0a
Show file tree
Hide file tree
Showing 53 changed files with 1,064 additions and 519 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,24 @@ You can build the docker images in your native host (Mac, Ubuntu, Windows, etc.)
* run `make docker`. For more build instructions see [fabric-ca README](https://github.com/hyperledger/fabric-ca)
* build fabric peer and orderer docker images and other ancillary images
* `cd $GOPATH/src/github.com/hyperledger/fabric`
* run `make docker` to build the docker images
* go to fabric-sdk-node/test/fixtures/channel
* run `make docker` to build the docker images (you may need to run `make docker-clean` first if you've built before)
* go to fabric-sdk-node/test/fixtures
* run `docker-compose up --force-recreate` to launch the network
* Now you are ready to run the tests:
* Clear out your previous key value stores that may have cached user enrollment certificates (`rm -rf /tmp/hfc-*`, `rm -rf ~/.hfc-key-store`)
* run 'gulp test' to execute the entire test suite (495+ test cases), or you can run them individually
* Test user management by member services with the following tests that exercise the fabric-ca-client package with a KeyValueStore implementations for a file-based KeyValueStore as well as a CouchDB KeyValueStore. To successfully run this test, you must first set up a CouchDB database instance on your local machine. Please see the instructions below.
* `test/integration/fabric-ca-services-tests.js`
* `test/integration/couchdb-fabricca-tests.js`
* `test/integration/cloudant-fabricca-tests.js`
* Test happy path from end to end, run `node test/integration/e2e.js`
* Test end to end one step at a time, make sure to follow this sequence:
* `node test/integration/e2e/create-channel.js`
* `node test/integration/e2e/join-channel.js`
* `node test/integration/e2e/install-chaincode.js`
* `node test/integration/e2e/instantiate-chaincode.js`
* `node test/integration/e2e/invoke-transaction.js`
* `node test/integration/e2e/query.js`

### Set Up CouchDB Database for couchdb-fabricca-tests.js

Expand Down
2 changes: 1 addition & 1 deletion fabric-ca-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fabric-ca-client",
"version": "0.1.2",
"version": "0.2.1",
"main": "index.js",
"repository": {
"type": "gerrit",
Expand Down
3 changes: 2 additions & 1 deletion fabric-client/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"EC": "fabric-client/lib/impl/bccsp_pkcs11.js"
},
"key-value-store": "fabric-client/lib/impl/FileKeyValueStore.js",
"nonce-size" : 24
"nonce-size" : 24,
"grpc-ssl-cipher-suites": "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384"
}
2 changes: 1 addition & 1 deletion fabric-client/lib/Chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -1394,7 +1394,7 @@ var Chain = class {
}
).catch(
function(err) {
logger.error('Failed Channels Query. Error: %s', err.stack ? err.stack : err);
logger.error(util.format('Failed Channels Query. Error: %j', err.stack ? {error: err.stack} : err));
return Promise.reject(err);
}
);
Expand Down
4 changes: 3 additions & 1 deletion fabric-client/lib/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

'use strict';

var Chain = require('./Chain.js');
var sdkUtils = require('./utils.js');
process.env.GRPC_SSL_CIPHER_SUITES = sdkUtils.getConfigSetting('grpc-ssl-cipher-suites');

var Chain = require('./Chain.js');
var logger = sdkUtils.getLogger('Client.js');
var api = require('./api.js');
var User = require('./User.js');
Expand Down
21 changes: 14 additions & 7 deletions fabric-client/lib/EventHub.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
'use strict';

var utils = require('./utils.js');
var Remote = require('./Remote.js');
var grpc = require('grpc');
var HashTable = require('hashtable');
var logger = utils.getLogger('EventHub.js');
Expand Down Expand Up @@ -77,10 +78,8 @@ var EventHub = class {
this.blockRegistrants = new Set();
// hashtable of clients registered for transactional events
this.txRegistrants = new HashTable();
// peer addr to connect to
// peer node to connect to
this.ep = null;
// grpc options
this.opts = null;
// grpc event client interface
this._client = null;
// grpc chat streaming interface
Expand All @@ -95,11 +94,19 @@ var EventHub = class {
* class creates a default eventHub that most Node clients can
* use (see eventHubConnect, eventHubDisconnect and getEventHub).
* @param {string} peeraddr peer url
* @param {object} opts grpc options for peer
* @param {object} opts An Object that may contain options to pass to grpcs calls
* <br>- pem {string} The certificate file, in PEM format,
* to use with the gRPC protocol (that is, with TransportCredentials).
* Required when using the grpcs protocol.
* <br>- ssl-target-name-override {string} Used in test environment only, when the server certificate's
* hostname (in the 'CN' field) does not match the actual host endpoint that the server process runs
* at, the application can work around the client TLS verify failure by setting this property to the
* value of the server certificate's hostname
* <br>- any other standard grpc call options will be passed to the grpc service calls directly
*/

setPeerAddr(peerUrl) {
this.ep = new utils.Endpoint(peerUrl, null);
setPeerAddr(peerUrl, opts) {
this.ep = new Remote(peerUrl, opts);
}

/**
Expand All @@ -119,7 +126,7 @@ var EventHub = class {
connect() {
if (this.connected) return;
if (!this.ep) throw Error('Must set peer address before connecting.');
this._client = new _events.Events(this.ep.addr, this.ep.creds, this.opts);
this._client = new _events.Events(this.ep._endpoint.addr, this.ep._endpoint.creds, this.ep._options);
this.call = this._client.chat();
this.connected = true;
// register txCallback to process txid callbacks
Expand Down
98 changes: 70 additions & 28 deletions fabric-client/lib/Remote.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

'use strict';

var api = require('./api.js');
var utils = require('./utils.js');

var grpc = require('grpc');
var urlParser = require('url');

var utils = require('./utils.js');
var logger = utils.getLogger('Remote.js');


Expand All @@ -31,45 +31,54 @@ var logger = utils.getLogger('Remote.js');
var Remote = class {

/**
* Constructs a Node with the endpoint configuration settings.
* Constructs an object with the endpoint configuration settings.
*
* @param {string} url The orderer URL with format of 'grpcs://host:port'.
* @param {opts} An Object that may contain options to override the global settings
* pem The certificate file, in PEM format,
* to use with the gRPC protocol (that is, with TransportCredentials).
* Required when using the grpcs protocol.
* @param {string} url The orderer URL with format of 'grpc(s)://host:port'.
* @param {object} opts An Object that may contain options to pass to grpcs calls
* <br>- pem {string} The certificate file, in PEM format,
* to use with the gRPC protocol (that is, with TransportCredentials).
* Required when using the grpcs protocol.
* <br>- ssl-target-name-override {string} Used in test environment only, when the server certificate's
* hostname (in the 'CN' field) does not match the actual host endpoint that the server process runs
* at, the application can work around the client TLS verify failure by setting this property to the
* value of the server certificate's hostname
* <br>- any other standard grpc call options will be passed to the grpc service calls directly
*/
constructor(url, opts) {
var pem = null;
if(opts) {
if(opts.pem) {
pem = opts.pem;
}
var ssl_target_name_override = '';
var default_authority = '';

if (opts && opts.pem) {
pem = opts.pem;
}

var ssl_target_name_override = 'tlsca';
var default_authority = 'tlsca';
if(opts && opts['ssl-target-name-override']) {
if (opts && opts['ssl-target-name-override']) {
ssl_target_name_override = opts['ssl-target-name-override'];
}
else {
ssl_target_name_override = utils.getConfigSetting('ssl-target-name-override','tlsca');
}
if(opts && opts['default-authority']) {
default_authority = opts['default-authority'];
}
else {
default_authority = utils.getConfigSetting('default-authority','tlsca');
default_authority = opts['ssl-target-name-override'];
}

// connection options
this._options = {};
if(ssl_target_name_override) this._options['grpc.ssl_target_name_override'] = ssl_target_name_override;
if(default_authority) this._options['grpc.default_authority'] = default_authority;
if (ssl_target_name_override !== '') {
this._options['grpc.ssl_target_name_override'] = ssl_target_name_override;
}

if (default_authority !== '') {
this._options['grpc.default_authority'] = default_authority;
}

for (let key in opts ? opts : {}) {
if (opts.hasOwnProperty(key)) {
if (key !== 'pem' && key !== 'ssl-target-name-override') {
this._options[key] = opts[key];
}
}
}

// service connection
this._url = url;
this._endpoint = new utils.Endpoint(url, pem);
this._endpoint = new Endpoint(url, pem);
}

/**
Expand All @@ -92,3 +101,36 @@ var Remote = class {
};

module.exports = Remote;

//
// The Endpoint class represents a remote grpc or grpcs target
//
var Endpoint = class {
constructor(url /*string*/ , pem /*string*/ ) {
var fs = require('fs'),
path = require('path');

var purl = urlParser.parse(url, true);
var protocol;
if (purl.protocol) {
protocol = purl.protocol.toLowerCase().slice(0, -1);
}
if (protocol === 'grpc') {
this.addr = purl.host;
this.creds = grpc.credentials.createInsecure();
} else if (protocol === 'grpcs') {
if(!(typeof pem === 'string')) {
throw new Error('PEM encoded certificate is required.');
}
this.addr = purl.host;
this.creds = grpc.credentials.createSsl(new Buffer(pem));
} else {
var error = new Error();
error.name = 'InvalidProtocol';
error.message = 'Invalid protocol: ' + protocol + '. URLs must begin with grpc:// or grpcs://';
throw error;
}
}
};

module.exports.Endpoint = Endpoint;
30 changes: 0 additions & 30 deletions fabric-client/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

'use strict';

var grpc = require('grpc');
var urlParser = require('url');
var util = require('util');
var winston = require('winston');
var fs = require('fs-extra');
Expand Down Expand Up @@ -334,34 +332,6 @@ module.exports.removeMSPManager = function(chainId) {
delete mspManagers[chainId];
};

//
// The Endpoint class represents a remote grpc or grpcs target
//
module.exports.Endpoint = class {
constructor(url /*string*/ , pem /*string*/ ) {
var purl = urlParser.parse(url, true);
var protocol;
if (purl.protocol) {
protocol = purl.protocol.toLowerCase().slice(0, -1);
}
if (protocol === 'grpc') {
this.addr = purl.host;
this.creds = grpc.credentials.createInsecure();
} else if (protocol === 'grpcs') {
if(!(typeof pem === 'string')) {
throw new Error('PEM encoded certificate is required.');
}
this.addr = purl.host;
this.creds = grpc.credentials.createSsl(new Buffer(pem));
} else {
var error = new Error();
error.name = 'InvalidProtocol';
error.message = 'Invalid protocol: ' + protocol + '. URLs must begin with grpc:// or grpcs://';
throw error;
}
}
};

//
// Other miscellaneous methods
//
Expand Down
2 changes: 1 addition & 1 deletion fabric-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fabric-client",
"version": "0.1.3",
"version": "0.2.1",
"main": "index.js",
"repository": {
"type": "gerrit",
Expand Down
5 changes: 5 additions & 0 deletions peer1.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN ECDSA PRIVATE KEY-----
MHcCAQEEII0oxsh+lV49AVCyYfqXr3QfvQ19rJl7VN/8g6nLCiCroAoGCCqGSM49
AwEHoUQDQgAEZibYpTur7h/LIkZkV1yr11mP0M4Hts+ARrky3r97WihvF0+TgxUI
UrFjEe4Yv+SIlz5+IE6BlNemaF67nUeD+Q==
-----END ECDSA PRIVATE KEY-----
12 changes: 6 additions & 6 deletions test/fixtures/channel/configtx.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ Organizations:
# AnchorPeers defines the location of peers which can be used
# for cross org gossip communication. Note, this value is only
# encoded in the genesis block in the Application section context
- Host: localhost
- Host: peer0
Port: 7051
- Host: localhost
- Host: peer1
Port: 7056

- &Org1
Expand Down Expand Up @@ -126,9 +126,9 @@ Organizations:
# AnchorPeers defines the location of peers which can be used
# for cross org gossip communication. Note, this value is only
# encoded in the genesis block in the Application section context
- Host: localhost
- Host: peer2
Port: 8051
- Host: localhost
- Host: peer3
Port: 8056

################################################################################
Expand All @@ -146,7 +146,7 @@ Orderer: &OrdererDefaults
OrdererType: solo

Addresses:
- orderer:7050
- orderer0:7050

# Batch Timeout: The amount of time to wait before creating a batch
BatchTimeout: 10s
Expand All @@ -170,7 +170,7 @@ Orderer: &OrdererDefaults
# Brokers: A list of Kafka brokers to which the orderer connects
# NOTE: Use IP:port notation
Brokers:
- orderer:9092
- orderer0:9092

# Organizations is the list of orgs which are defined as participants on
# the orderer side of the network
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBcjCCARigAwIBAwICA+gwCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwLb3JkZXJl
ck9yZzAwHhcNMTcwMjIwMTkwNjEwWhcNMTgwMjIwMTkwNjEwWjAWMRQwEgYDVQQD
DAtvcmRlcmVyT3JnMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABK8Sv0EA9h06
fmBkUCO+D/b/2INZ2huy+W/HCxSF22c7WGoJbRzQcWtQmW1KqZowUk86RcxVfFqv
jEMFVXzV38SjVjBUMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFCVakuvq
xEcK8pYMf/Hw8hsexRMTMB8GA1UdIwQYMBaAFCVakuvqxEcK8pYMf/Hw8hsexRMT
MAoGCCqGSM49BAMCA0gAMEUCIQCmXgDSRTyxpSk+PXg0FNlYZ4ijTVwKgLkYVhod
zZPfngIgO4y0p3Fs/gNsJYrroKaaVDe955KrPp/O55jYDKAD/oY=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBbDCCARKgAwIBAwICA+gwCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwIcGVlck9y
ZzAwHhcNMTcwMjIwMTkwNjEwWhcNMTgwMjIwMTkwNjEwWjATMREwDwYDVQQDDAhw
ZWVyT3JnMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKJfDc/CcaiHRipTG2AB
K5fA0LO9SOlbtC9bZcjLo/xsL157p+3QB3UVF3gt7nkwgMs/ul3FhSEFTk2EVNlF
1QCjVjBUMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFFQzuQR1RZP/Qn/B
NDtGSa8n4eN/MB8GA1UdIwQYMBaAFFQzuQR1RZP/Qn/BNDtGSa8n4eN/MAoGCCqG
SM49BAMCA0gAMEUCIAuG+/Fy3x9JXAD1/rFsu3ZpCKbXiXZLGF7P6Gma8is5AiEA
pSQpRcdukxe4zvcfRmNBjMbNLWCoWlHSQA2jD678QGE=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBbDCCARKgAwIBAwICA+gwCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwIcGVlck9y
ZzEwHhcNMTcwMjIwMTkwNjEwWhcNMTgwMjIwMTkwNjEwWjATMREwDwYDVQQDDAhw
ZWVyT3JnMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ2S+UvyFgFZYL6qcrKo
zy72Nkc/RQVzg1VfwC3X7QcnHEVBuCzba1nxdDVE8XPnhmKBWLKh0adn6GKUZpyf
mbKjVjBUMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFAQlMVsXlKGMEWPf
KMMM6QVASnlPMB8GA1UdIwQYMBaAFAQlMVsXlKGMEWPfKMMM6QVASnlPMAoGCCqG
SM49BAMCA0gAMEUCIHr4AD6Xx3R6zFCsveIMnWao9Us88/0uGHoT4ELmMhA1AiEA
yzfXU5qHp3xBJ1BrKOGi71UmQZVwWfO26INhxcfpCAg=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBbDCCARKgAwIBAwICA+gwCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwIcGVlck9y
ZzIwHhcNMTcwMjIwMTkwNjExWhcNMTgwMjIwMTkwNjExWjATMREwDwYDVQQDDAhw
ZWVyT3JnMjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH3IweQK1AJdcV3FF27a
gNKhy13Nz2OguzsmUbW85/7pReenAWzs89rEApHXoJqUtNzdZfaLkcq32E1Ilk3N
oN2jVjBUMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFEhOilIyGA53r9Zo
O5GQP0RSZcQ1MB8GA1UdIwQYMBaAFEhOilIyGA53r9ZoO5GQP0RSZcQ1MAoGCCqG
SM49BAMCA0gAMEUCIQD+/5z68ewJarixMgYrg/MwyTMwX7ikCaCgU5TN2MU1PQIg
Qe+klrq6COxsmrctClV64Wj4zhGTOhaZG1yN24OXukQ=
-----END CERTIFICATE-----
Loading

0 comments on commit 3afcb0a

Please sign in to comment.