Skip to content

Commit

Permalink
FAB-1453 Use Identity class in User.js
Browse files Browse the repository at this point in the history
the new Identity class abstracts out the management of
certificates and signature verification capabilities, as well as
relationship to MSP implementations. The User class needs to use
the Identity class to manage serialization (to send certificates
to peers along with signatures) and signature verification

The following tests can successfully run with the latest fabric:
- endorser-tests.js
- end-to-end.js (step1, step2)

Change-Id: Ida531d565f985937aeca736832bc33ab29ca475d
Signed-off-by: Jim Zhang <jzhang@us.ibm.com>
  • Loading branch information
jimthematrix committed Dec 21, 2016
1 parent 669acce commit 17635eb
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 168 deletions.
7 changes: 5 additions & 2 deletions hfc-cop/lib/FabricCOPImpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ var FabricCOPServices = class {
* @param req Enrollment request
* @param {string} req.enrollmentID The registered ID to use for enrollment
* @param {string} req.enrollmentSecret The secret associated with the enrollment ID
* @returns Promise for [Enrollment]{@link module:api.Enrollment}
* @returns Promise for an object with "key" for private key and "certificate" for the signed certificate
*/
enroll(req) {
var self = this;
Expand Down Expand Up @@ -107,7 +107,10 @@ var FabricCOPServices = class {
self._fabricCOPClient.enroll(req.enrollmentID, req.enrollmentSecret, csr)
.then(
function (csrPEM) {
return resolve(new api.Enrollment(privateKey, csrPEM));
return resolve({
key: privateKey,
certificate: csrPEM
});
},
function (err) {
return reject(err);
Expand Down
16 changes: 8 additions & 8 deletions hfc/lib/Chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,9 @@ var Chain = class {
return self._clientContext.getUserContext()
.then(
function(userContext) {
header = Chain._buildHeader(userContext.getEnrollment().certificate, request.chainId, 'lccc', request.txId, request.nonce);
header = Chain._buildHeader(userContext.getIdentity(), request.chainId, 'lccc', request.txId, request.nonce);
proposal = self._buildProposal(lcccSpec, header);
let signed_proposal = self._signProposal(userContext.getEnrollment(), proposal);
let signed_proposal = self._signProposal(userContext.getSigningIdentity(), proposal);

return Chain._sendPeersProposal(request.targets, signed_proposal);
}
Expand Down Expand Up @@ -452,9 +452,9 @@ var Chain = class {
return this._clientContext.getUserContext()
.then(
function(userContext) {
header = Chain._buildHeader(userContext.getEnrollment().certificate, request.chainId, request.chaincodeId, request.txId, request.nonce);
header = Chain._buildHeader(userContext.getIdentity(), request.chainId, request.chaincodeId, request.txId, request.nonce);
proposal = self._buildProposal(invokeSpec, header);
let signed_proposal = self._signProposal(userContext.getEnrollment(), proposal);
let signed_proposal = self._signProposal(userContext.getSigningIdentity(), proposal);

return Chain._sendPeersProposal(request.targets, signed_proposal);
}
Expand Down Expand Up @@ -567,7 +567,7 @@ var Chain = class {
return this._clientContext.getUserContext()
.then(
function(userContext) {
let sig = self.cryptoPrimitives.sign(userContext.getEnrollment().privateKey, payload_bytes);
let sig = self.cryptoPrimitives.sign(userContext.getSigningIdentity().key, payload_bytes);
let signature = Buffer.from(sig.toDER());

// building manually or will get protobuf errors on send
Expand Down Expand Up @@ -645,7 +645,7 @@ var Chain = class {

let signatureHeader = new _commonProto.SignatureHeader();

signatureHeader.setCreator(Buffer.from(creator));
signatureHeader.setCreator(creator.serialize());
signatureHeader.setNonce(nonce);

let header = new _commonProto.Header();
Expand Down Expand Up @@ -725,10 +725,10 @@ var Chain = class {
/**
* @private
*/
_signProposal(enrollment, proposal) {
_signProposal(signingIdentity, proposal) {
let proposal_bytes = proposal.toBuffer();
// sign the proposal
let sig = this.cryptoPrimitives.sign(enrollment.privateKey, proposal_bytes);
let sig = this.cryptoPrimitives.sign(signingIdentity.key, proposal_bytes);
let signature = Buffer.from(sig.toDER());

logger.debug('_signProposal - signature::'+JSON.stringify(signature));
Expand Down
82 changes: 62 additions & 20 deletions hfc/lib/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

var util = require('util');
var sdkUtils = require('./utils.js');
var api = require('./api.js');
var logger = sdkUtils.getLogger('Client.js');
var Identity = require('./msp/identity.js');
var MSP = require('./msp/msp.js');

/**
* The User class represents users that have been enrolled and represented by
Expand Down Expand Up @@ -59,10 +62,20 @@ var User = class {
}

this._enrollmentSecret = '';
this._enrollment = null;
this._identity = null;
this._signingIdentity = null;

this._client = client;
this.cryptoPrimitives = sdkUtils.getCryptoSuite();

// TODO: this should be using config properties obtained from the environment
this.mspImpl = new MSP({
trustedCerts: [],
signer: 'blah',
admins: [],
id: 'DEFAULT',
cryptoSuite: this.cryptoPrimitives
});
}

/**
Expand Down Expand Up @@ -106,27 +119,43 @@ var User = class {
}

/**
* Get the enrollment object for this User instance
* @returns {Enrollment} the enrollment object
* Get the {@link Identity} object for this User instance, used to verify signatures
* @returns {Identity} the identity object that encapsulates the user's enrollment certificate
*/
getIdentity() {
return this._identity;
}

/**
* Get the {@link SigningIdentity} object for this User instance, used to generate signatures
* @returns {SigningIdentity} the identity object that encapsulates the user's private key for signing
*/
getEnrollment() {
return this._enrollment;
getSigningIdentity() {
return this._signingIdentity;
}

/**
* Set the enrollment object for this User instance
* @param {Enrollment} the enrollment object
* @param {Key} privateKey the private key object
* @param {string} certificate the PEM-encoded string of certificate
*/
setEnrollment(enrollment) {
if (typeof enrollment.privateKey === 'undefined' || enrollment.privateKey === null || enrollment.privateKey === '') {
throw new Error('Invalid enrollment object. Must have a valid private key.');
setEnrollment(privateKey, certificate) {
if (typeof privateKey === 'undefined' || privateKey === null || privateKey === '') {
throw new Error('Invalid parameter. Must have a valid private key.');
}

if (typeof enrollment.certificate === 'undefined' || enrollment.certificate === null || enrollment.certificate === '') {
throw new Error('Invalid enrollment object. Must have a valid certificate.');
if (typeof certificate === 'undefined' || certificate === null || certificate === '') {
throw new Error('Invalid parameter. Must have a valid certificate.');
}

this._enrollment = enrollment;
var pubKey = this.cryptoPrimitives.importKey(certificate, { algorithm: api.CryptoAlgorithms.X509Certificate });
var identity = new Identity('testIdentity', certificate, pubKey, this.mspImpl);
this._identity = identity;

// TODO: to be encapsulated by a new class SigningIdentity
this._signingIdentity = {
key: privateKey
};
}

/**
Expand Down Expand Up @@ -155,7 +184,7 @@ var User = class {
* @returns {boolean} True if enrolled; otherwise, false.
*/
isEnrolled() {
return this._enrollment !== null;
return this._identity !== null && this._signingIdentity != null;
}

/**
Expand All @@ -174,15 +203,21 @@ var User = class {
this._roles = state.roles;
this._affiliation = state.affiliation;
this._enrollmentSecret = state.enrollmentSecret;
this._enrollment = state.enrollment;

var self = this;

var pubKey = this.cryptoPrimitives.importKey(state.enrollment.identity.certificate, { algorithm: api.CryptoAlgorithms.X509Certificate });
var identity = new Identity(state.enrollment.identity.id, state.enrollment.identity.certificate, pubKey, this.mspImpl);
this._identity = identity;

// during serialization (see toString() below) only the key's SKI are saved
// swap out that for the real key from the crypto provider
var promise = this.cryptoPrimitives.getKey(this._enrollment.privateKey)
.then(function(key) {
self._enrollment.privateKey = key;
var promise = this.cryptoPrimitives.getKey(state.enrollment.signingIdentity)
.then(function(privateKey) {
self._signingIdentity = {
key: privateKey
};

return self;
});

Expand All @@ -194,9 +229,16 @@ var User = class {
* @return {string} The state of this member as a string
*/
toString() {
var serializedEnrollment = (this._enrollment) ? Object.assign({}, this._enrollment) : null;
if (this._enrollment && this._enrollment.privateKey) {
serializedEnrollment.privateKey = this._enrollment.privateKey.getSKI();
var serializedEnrollment = {};
if (this._signingIdentity) {
serializedEnrollment.signingIdentity = this._signingIdentity.key.getSKI();
}

if (this._identity) {
serializedEnrollment.identity = {
id: this._identity.getId(),
certificate: this._identity._certificate
};
}

var state = {
Expand Down
74 changes: 0 additions & 74 deletions hfc/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,77 +272,3 @@ module.exports.CryptoAlgorithms = {
// X509Certificate Label for X509 certificate related operation
X509Certificate: 'X509Certificate'
};

/**
* Represents enrollment data for a user.
*
* @class
*/
module.exports.Enrollment = class {

constructor(key, cert) {
/**
* @member {Key} privateKey private key generated locally by the SDK
* @memberof module:api.Enrollment.prototype
*/
this.privateKey = key;

/**
* @member {string} certificate HEX encoded string for the certificate issued by member services after successful enrollment
* @memberof module:api.Enrollment.prototype
*/
this.certificate = cert;
}
};

/**
* The base Certificate class
*
* @class
*/
module.exports.Certificate = class {

constructor(cert, privateKey) {
/**
* @member {buffer} cert The certificate
* @memberof module:api.Certificate
*/
this._cert = cert;

/**
* @member {buffer} privateKey The private key
* @memberof module:api.Certificate
*/
this._privateKey = privateKey;
}

encode() {
return this._cert;
}
};

/**
* Enrollment certificate. These certificates are nominal.
*
* @class
*/
module.exports.ECert = class extends module.exports.Certificate {

constructor(cert, privateKey) {
super(cert, privateKey);
}

};

/**
* Transaction certificate. These certificates are anonymous.
*
* @class
*/
module.exports.TCert = class extends module.exports.Certificate {

constructor(publicKey, privateKey) {
super(publicKey, privateKey);
}
};

Loading

0 comments on commit 17635eb

Please sign in to comment.