diff --git a/hfc/lib/X509Certificate.js b/hfc/lib/X509Certificate.js
deleted file mode 100644
index eb781aae4e..0000000000
--- a/hfc/lib/X509Certificate.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- Copyright 2016 IBM All Rights Reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-'use strict';
-
-var api = require('./api.js');
-var utils = require('./utils.js');
-var certPaser = require('./utils-x509cert.js');
-
-/**
- * A model to represent x.509 certificate
- *
- * @class
- */
-var X509Certificate = class {
-
- constructor(buffer) {
- debug('cert:', JSON.stringify(buffer));
- // convert certBuffer to arraybuffer
- var certBuffer = utils.toArrayBuffer(buffer);
- // parse the DER-encoded buffer
- var asn1 = certPaser.org.pkijs.fromBER(certBuffer);
- this._cert = {};
- try {
- this._cert = new certPaser.org.pkijs.simpl.CERT({schema: asn1.result});
- debug('decoded certificate:\n', JSON.stringify(this._cert, null, 4));
- } catch (ex) {
- debug('error parsing certificate bytes: ', ex);
- throw ex;
- }
- }
-
- /**
- * What would be a suitable description of this method?
- *
- * @param {Object} Object ID
- */
- criticalExtension(oid) {
- var ext;
- debug('oid: ', oid);
- this._cert.extensions.some(function (extension) {
- debug('extnID: ', extension.extnID);
- if (extension.extnID === oid) {
- ext = extension;
- return true;
- }
- });
- debug('found extension: ', ext);
- debug('extValue: ', _toBuffer(ext.extnValue.value_block.value_hex));
- return _toBuffer(ext.extnValue.value_block.value_hex);
- }
-
-};
-
-// utility function to convert Javascript arraybuffer to Node buffers
-function _toBuffer(ab) {
- var buffer = new Buffer(ab.byteLength);
- var view = new Uint8Array(ab);
- for (var i = 0; i < buffer.length; ++i) {
- buffer[i] = view[i];
- }
- return buffer;
-}
-
-module.exports = X509Certificate;
diff --git a/hfc/lib/api.js b/hfc/lib/api.js
index 5bd21750af..0c3127bff2 100644
--- a/hfc/lib/api.js
+++ b/hfc/lib/api.js
@@ -95,8 +95,9 @@ module.exports.CryptoSuite = class {
* Imports a key from its raw representation using opts.
* @param {byte[]} raw Raw bytes of the key to import
* @param {Object} opts
- * algorithm: an identifier for the algorithm to be used
- * ephemeral: true if the key to generate has to be ephemeral
+ *
`type`: type of information that 'raw' represents: x509 certificate,
+ *
`algorithm`: an identifier for the algorithm to be used
+ *
`ephemeral`: true if the key to generate has to be ephemeral
* @returns {Key} An instance of the Key class wrapping the raw key bytes
*/
importKey(raw, opts) {}
@@ -213,6 +214,65 @@ module.exports.Key = class {
toBytes() {}
};
+module.exports.CryptoAlgorithms = {
+ // ECDSA Elliptic Curve Digital Signature Algorithm (key gen, import, sign, verify),
+ // at default security level.
+ // Each BCCSP may or may not support default security level. If not supported than
+ // an error will be returned.
+ ECDSA: 'ECDSA',
+ // ECDSA Elliptic Curve Digital Signature Algorithm over P-256 curve
+ ECDSAP256: 'ECDSAP256',
+ // ECDSA Elliptic Curve Digital Signature Algorithm over P-384 curve
+ ECDSAP384: 'ECDSAP384',
+ // ECDSAReRand ECDSA key re-randomization
+ ECDSAReRand: 'ECDSA_RERAND',
+
+ // RSA at the default security level.
+ // Each BCCSP may or may not support default security level. If not supported than
+ // an error will be returned.
+ RSA: 'RSA',
+ // RSA at 1024 bit security level.
+ RSA1024: 'RSA1024',
+ // RSA at 2048 bit security level.
+ RSA2048: 'RSA2048',
+ // RSA at 3072 bit security level.
+ RSA3072: 'RSA3072',
+ // RSA at 4096 bit security level.
+ RSA4096: 'RSA4096',
+
+ // AES Advanced Encryption Standard at the default security level.
+ // Each BCCSP may or may not support default security level. If not supported than
+ // an error will be returned.
+ AES: 'AES',
+ // AES Advanced Encryption Standard at 128 bit security level
+ AES128: 'AES128',
+ // AES Advanced Encryption Standard at 192 bit security level
+ AES192: 'AES192',
+ // AES Advanced Encryption Standard at 256 bit security level
+ AES256: 'AES256',
+
+ // HMAC keyed-hash message authentication code
+ HMAC: 'HMAC',
+ // HMACTruncated256 HMAC truncated at 256 bits.
+ HMACTruncated256: 'HMAC_TRUNCATED_256',
+
+ // SHA Secure Hash Algorithm using default family.
+ // Each BCCSP may or may not support default security level. If not supported than
+ // an error will be returned.
+ SHA: 'SHA',
+ // SHA256
+ SHA256: 'SHA256',
+ // SHA384
+ SHA384: 'SHA384',
+ // SHA3_256
+ SHA3_256: 'SHA3_256',
+ // SHA3_384
+ SHA3_384: 'SHA3_384',
+
+ // X509Certificate Label for X509 certificate related operation
+ X509Certificate: 'X509Certificate'
+};
+
/**
* Represents enrollment data for a user.
*
@@ -235,23 +295,6 @@ module.exports.Enrollment = class {
}
};
-/**
- * @class
- */
-module.exports.PrivacyLevel = {
- /**
- * @member {constant} Nominal Representing a certain identity
- * @memberof module:api.PrivacyLevel
- */
- Nominal: 0,
-
- /**
- * @member {constant} Anonymous Anonymous
- * @memberof module:api.PrivacyLevel
- */
- Anonymous: 1
-};
-
/**
* The base Certificate class
*
@@ -259,7 +302,7 @@ module.exports.PrivacyLevel = {
*/
module.exports.Certificate = class {
- constructor(cert, privateKey, privacyLevel) {
+ constructor(cert, privateKey) {
/**
* @member {buffer} cert The certificate
* @memberof module:api.Certificate
@@ -271,12 +314,6 @@ module.exports.Certificate = class {
* @memberof module:api.Certificate
*/
this._privateKey = privateKey;
-
- /**
- * @member {module:api.PrivacyLevel} privacyLevel - Denoting if the Certificate is anonymous or carrying its owner's identity.
- * @memberof module:api.Certificate
- */
- this._privacyLevel = privacyLevel;
}
encode() {
@@ -292,7 +329,7 @@ module.exports.Certificate = class {
module.exports.ECert = class extends module.exports.Certificate {
constructor(cert, privateKey) {
- super(cert, privateKey, module.exports.PrivacyLevel.Nominal);
+ super(cert, privateKey);
}
};
@@ -305,7 +342,7 @@ module.exports.ECert = class extends module.exports.Certificate {
module.exports.TCert = class extends module.exports.Certificate {
constructor(publicKey, privateKey) {
- super(publicKey, privateKey, module.exports.PrivacyLevel.Anonymous);
+ super(publicKey, privateKey);
}
};
diff --git a/hfc/lib/impl/CryptoSuite_ECDSA_AES.js b/hfc/lib/impl/CryptoSuite_ECDSA_AES.js
index 78d72d0b8f..96875ddc34 100644
--- a/hfc/lib/impl/CryptoSuite_ECDSA_AES.js
+++ b/hfc/lib/impl/CryptoSuite_ECDSA_AES.js
@@ -157,7 +157,6 @@ var CryptoSuite_ECDSA_AES = class extends api.CryptoSuite {
/**
* This is an implementation of {@link module:api.CryptoSuite#importKey}
- * To be implemented
*/
importKey(raw, opts) {
if (!opts)
@@ -166,7 +165,7 @@ var CryptoSuite_ECDSA_AES = class extends api.CryptoSuite {
if (!opts.algorithm)
throw new Error('Parameter "opts" missing required field "algorithm"');
- if (opts.algorithm === 'X509Certificate') {
+ if (opts.algorithm === api.CryptoAlgorithms.X509Certificate) {
// importing public key from an x.509 certificate
var pemString = Buffer.from(raw).toString();
try {
diff --git a/hfc/lib/impl/ecdsa/key.js b/hfc/lib/impl/ecdsa/key.js
index 4f1f84efc2..68677995b5 100644
--- a/hfc/lib/impl/ecdsa/key.js
+++ b/hfc/lib/impl/ecdsa/key.js
@@ -80,6 +80,7 @@ module.exports = class ECDSA_KEY {
buff = pointToOctet(this.getPublicKey()._key);
}
+ // always use SHA256 regardless of the key size in effect
return Hash.sha2_256(buff);
}
diff --git a/hfc/lib/msp/identity.js b/hfc/lib/msp/identity.js
new file mode 100644
index 0000000000..3316230f01
--- /dev/null
+++ b/hfc/lib/msp/identity.js
@@ -0,0 +1,120 @@
+'use strict';
+
+var grpc = require('grpc');
+
+var identityProto = grpc.load(__dirname + '/../protos/identity.proto').msp;
+
+/**
+ * This interface is shared within the peer and client API of the membership service provider.
+ * Identity interface defines operations associated to a "certificate".
+ * That is, the public part of the identity could be thought to be a certificate,
+ * and offers solely signature verification capabilities. This is to be used
+ * at the client side when validating certificates that endorsements are signed
+ * with, and verifying signatures that correspond to these certificates.
+ *
+ * @class
+ */
+var Identity = class {
+ /**
+ * @param {string} id Identifier of this identity object
+ * @param {string} certificate HEX string for the PEM encoded certificate
+ * @param {Key} publicKey The public key represented by the certificate
+ * @param {MSP} msp The associated MSP that manages this identity
+ */
+ constructor(id, certificate, publicKey, msp) {
+ if (!id)
+ throw new Error('Missing required parameter "id".');
+
+ if (!certificate)
+ throw new Error('Missing required parameter "certificate".');
+
+ if (!publicKey)
+ throw new Error('Missing required parameter "publicKey".');
+
+ if (!msp)
+ throw new Error('Missing required parameter "msp".');
+
+ this._id = id;
+ this._certificate = certificate;
+ this._publicKey = publicKey;
+ this._msp = msp;
+ }
+
+ /**
+ * Returns the identifier of this identity
+ * @returns {string}
+ */
+ getId() {
+ return this._id;
+ }
+
+ /**
+ * Returns the identifier of the Membser Service Provider that manages
+ * this identity in terms of being able to understand the key algorithms
+ * and have access to the trusted roots needed to validate it
+ * @returns {string}
+ */
+ getMSPId() {
+ return this._msp.getId();
+ }
+
+ /**
+ * This uses the rules that govern this identity to validate it.
+ * E.g., if it is a fabric TCert implemented as identity, validate
+ * will check the TCert signature against the assumed root certificate
+ * authority.
+ * @returns {boolean}
+ */
+ isValid() {
+ this._msp.validate(this);
+ }
+
+ /**
+ * Returns the organization units this identity is related to
+ * as long as this is public information. In certain implementations
+ * this could be implemented by certain attributes that are publicly
+ * associated to that identity, or the identifier of the root certificate
+ * authority that has provided signatures on this certificate.
+ * Examples:
+ * - OrganizationUnit of a fabric-tcert that was signed by TCA under name
+ * "Organization 1", would be "Organization 1".
+ * - OrganizationUnit of an alternative implementation of tcert signed by a public
+ * CA used by organization "Organization 1", could be provided in the clear
+ * as part of that tcert structure that this call would be able to return.
+ * @returns {string}
+ */
+ getOrganizationUnits() {
+ return 'dunno!';
+ }
+
+ /**
+ * Verify a signature over some message using this identity as reference
+ * @param {byte[]} msg The message to be verified
+ * @param {byte[]} signature The signature generated against the message "msg"
+ * @param {Object} opts Options include 'policy' and 'label'
+ */
+ verify(msg, signature, opts) {
+ return this._msp.cryptoSuite.verify(this._publicKey, signature, msg);
+ }
+
+ /**
+ * Verify attributes against the given attribute spec
+ * TODO: when this method's design is finalized
+ */
+ verifyAttributes(proof, attributeProofSpec) {
+ return true;
+ }
+
+ /**
+ * Converts this identity to bytes
+ * @returns {Buffer} protobuf-based serialization with two fields: "mspid" and "certificate PEM bytes"
+ */
+ serialize() {
+ var serializedIdentity = new identityProto.SerializedIdentity();
+ serializedIdentity.Mspid = this.getMSPId();
+ serializedIdentity.IdBytes = Buffer.from(this._certificate);
+ return serializedIdentity.toBuffer();
+ }
+};
+
+module.exports = Identity;
diff --git a/hfc/lib/msp/msp.js b/hfc/lib/msp/msp.js
new file mode 100644
index 0000000000..f553616d3d
--- /dev/null
+++ b/hfc/lib/msp/msp.js
@@ -0,0 +1,113 @@
+'use strict';
+
+var api = require('../api.js');
+var Identity = require('./identity.js');
+var utils = require('../utils.js');
+var logger = utils.getLogger('msp.js');
+
+var grpc = require('grpc');
+var identityProto = grpc.load(__dirname + '/../protos/identity.proto').msp;
+
+/**
+ * MSP is the minimal Membership Service Provider Interface to be implemented
+ * to manage identities (in terms of signing and signature verification) represented
+ * by private keys and certificates generated from different algorithms (ECDSA, RSA, etc)
+ * and PKIs (software-managed or HSM based)
+ * @class
+ */
+var MSP = class {
+ /**
+ * Setup the MSP instance according to configuration information
+ * @param {Object} config A configuration object specific to the implementation. For this
+ * implementation it requires the following fields:
+ *
`trustedCerts`: array of {@link Identity} to establish trust anchorts for validating signing certificates
+ *
`signer`: {@link SigningIdentity} signing identity
+ *
`admins`: array of {@link Identity} representing admin privileges
+ *
`id`: {string} value for the identifier of this instance
+ *
`cryptoSuite': the underlying {@link module:api.CryptoSuite} for crypto primitive operations
+ */
+ constructor(config) {
+ if (!config)
+ throw new Error('Missing required parameter "config"');
+
+ if (!config.trustedCerts)
+ throw new Error('Parameter "config" missing required field "trustedCerts"');
+
+ if (!config.signer)
+ throw new Error('Parameter "config" missing required field "signer"');
+
+ if (!config.admins)
+ throw new Error('Parameter "config" missing required field "admins"');
+
+ if (!config.id)
+ throw new Error('Parameter "config" missing required field "id"');
+
+ if (!config.cryptoSuite)
+ throw new Error('Parameter "config" missing required field "cryptoSuite"');
+
+ this._trustedCerts = config.trustedCerts;
+ this._signer = config.signer;
+ this._admins = config.admins;
+ this.cryptoSuite = config.cryptoSuite;
+ this._id = config.id;
+ }
+
+ /**
+ * Get provider identifier
+ * @returns {string}
+ */
+ getId() {
+ return this._id;
+ }
+
+ /**
+ * Obtain the policy to govern changes
+ * @returns {Object}
+ */
+ getPolicy() {
+ throw new Error('Not implemented yet');
+ }
+
+ /**
+ * Returns a signing identity corresponding to the provided identifier
+ * @param {string} identifier The identifier of the requested identity object
+ * @returns {SigningIdentity}
+ */
+ getSigningIdentity(identifier) {
+ throw new Error('Not implemented yet');
+ }
+
+ /**
+ * Returns the default signing identity
+ * @returns {SigningIdentity}
+ */
+ getDefaultSigningIdentity() {
+ return this._signer;
+ }
+
+ /**
+ * DeserializeIdentity deserializes an identity
+ * @param {byte[]} serializedIdentity A protobuf-based serialization of an object with
+ * two fields: mspid and idBytes for certificate PEM bytes
+ * @returns {Identity}
+ */
+ deserializeIdentity(serializedIdentity) {
+ var sid = identityProto.SerializedIdentity.decode(serializedIdentity);
+ var cert = sid.IdBytes.toBinary();
+ logger.debug('Encoded cert from deserialized identity: %s', cert);
+ var publicKey = this.cryptoSuite.importKey(cert, { algorithm: api.CryptoAlgorithms.X509Certificate });
+ // TODO: the id of the new Identity instance should probably be derived from the subject info in the cert?
+ return new Identity('SomeDummyValue', cert, publicKey, this);
+ }
+
+ /**
+ * Checks whether the supplied identity is valid
+ * @param {Identity} id
+ * @returns {boolean}
+ */
+ validate(id) {
+ return true;
+ }
+};
+
+module.exports = MSP;
\ No newline at end of file
diff --git a/hfc/lib/protos/ca.proto b/hfc/lib/protos/ca.proto
deleted file mode 100644
index a7a0feb692..0000000000
--- a/hfc/lib/protos/ca.proto
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
-Copyright IBM Corp. 2016 All Rights Reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-syntax = "proto3";
-
-package protos;
-
-import "google/protobuf/timestamp.proto";
-
-
-// Enrollment Certificate Authority (ECA).
-//
-service ECAP { // public service
- rpc ReadCACertificate(Empty) returns (Cert);
- rpc CreateCertificatePair(ECertCreateReq) returns (ECertCreateResp);
- rpc ReadCertificatePair(ECertReadReq) returns (CertPair);
- rpc ReadCertificateByHash(Hash) returns (Cert);
- rpc RevokeCertificatePair(ECertRevokeReq) returns (CAStatus); // a user can revoke only his/her own cert
-}
-
-service ECAA { // admin service
- rpc RegisterUser(RegisterUserReq) returns (Token);
- rpc ReadUserSet(ReadUserSetReq) returns (UserSet);
- rpc RevokeCertificate(ECertRevokeReq) returns (CAStatus); // an admin can revoke any cert
- rpc PublishCRL(ECertCRLReq) returns (CAStatus); // publishes CRL in the blockchain
-}
-
-// Transaction Certificate Authority (TCA).
-//
-service TCAP { // public service
- rpc ReadCACertificate(Empty) returns (Cert);
- rpc CreateCertificateSet(TCertCreateSetReq) returns (TCertCreateSetResp);
- rpc RevokeCertificate(TCertRevokeReq) returns (CAStatus); // a user can revoke only his/her cert
- rpc RevokeCertificateSet(TCertRevokeSetReq) returns (CAStatus); // a user can revoke only his/her certs
-}
-
-service TCAA { // admin service
- rpc RevokeCertificate(TCertRevokeReq) returns (CAStatus); // an admin can revoke any cert
- rpc RevokeCertificateSet(TCertRevokeSetReq) returns (CAStatus); // an admin can revoke any cert
- rpc PublishCRL(TCertCRLReq) returns (CAStatus); // publishes CRL in the blockchain
-}
-
-// TLS Certificate Authority (TLSCA)
-//
-service TLSCAP { // public service
- rpc ReadCACertificate(Empty) returns (Cert);
- rpc CreateCertificate(TLSCertCreateReq) returns (TLSCertCreateResp);
- rpc ReadCertificate(TLSCertReadReq) returns (Cert);
- rpc RevokeCertificate(TLSCertRevokeReq) returns (CAStatus); // a user can revoke only his/her cert
-}
-
-service TLSCAA { // admin service
- rpc RevokeCertificate(TLSCertRevokeReq) returns (CAStatus); // an admin can revoke any cert
-}
-
-// Attribute Certificate Authority (ACA).
-//
-service ACAP { // public service
- rpc ReadCACertificate(Empty) returns (Cert);
- rpc RequestAttributes(ACAAttrReq) returns (ACAAttrResp);
- rpc FetchAttributes(ACAFetchAttrReq) returns (ACAFetchAttrResp);
-}
-
-// Status codes shared by both CAs.
-//
-message CAStatus {
- enum StatusCode {
- OK = 0;
- UNKNOWN_ERROR = 1;
- }
- StatusCode status = 1;
-}
-
-
-// Empty message.
-message Empty {
-}
-
-// Uniquely identifies a user towards either CA.
-message Identity {
- string id = 1;
-}
-
-message Token {
- bytes tok = 1;
-}
-
-message Hash {
- bytes hash = 1;
-}
-
-// Public/private keys.
-enum CryptoType {
- ECDSA = 0;
- RSA = 1;
- DSA = 2;
-}
-
-message PublicKey {
- CryptoType type = 1;
- bytes key = 2; // DER / ASN.1
-}
-
-message PrivateKey {
- CryptoType type = 1;
- bytes key = 2; // DER / ASN.1
-}
-
-// Signature.
-//
-message Signature {
- CryptoType type = 1;
- bytes r = 2;
- bytes s = 3;
-}
-
-// User registration.
-//
-enum Role {
- NONE = 0;
- CLIENT = 1; // powers of 2 to | different roles
- PEER = 2;
- VALIDATOR = 4;
- AUDITOR = 8;
- ALL = 0xFFFF;
-}
-
-message Registrar {
- Identity id = 1; // The identity of the registrar
- repeated string roles = 2; // Roles that the registrar can register
- repeated string delegateRoles = 3; // Roles that the registrar can give to another to register
-}
-
-message RegisterUserReq {
- Identity id = 1;
- Role role = 2;
- string affiliation = 4; // Skipping field number 3 to maintain backward compatibility. It was used before for the primary account.
- Registrar registrar = 5;
- Signature sig = 6;
-}
-
-message ReadUserSetReq {
- Identity req = 1;
- Role role = 2; // bitmask
- Signature sig = 3; // sign(priv, req | id | role)
-}
-
-message User {
- Identity id = 1;
- Role role = 2;
-}
-
-message UserSet {
- repeated User users = 1;
-}
-
-// Certificate requests.
-//
-message ECertCreateReq {
- google.protobuf.Timestamp ts = 1;
- Identity id = 2;
- Token tok = 3;
- PublicKey sign = 4;
- PublicKey enc = 5;
- Signature sig = 6; // sign(priv, ts | id | tok | sign | enc)
-}
-
-message ECertCreateResp {
- CertPair certs = 1;
- Token chain = 2;
- bytes pkchain = 5;
- Token tok = 3;
- FetchAttrsResult fetchResult = 4;
-}
-
-message ECertReadReq {
- Identity id = 1;
-}
-
-message ECertRevokeReq {
- Identity id = 1; // user or admin whereby users can only revoke their own cert
- Cert cert = 2; // cert to revoke
- Signature sig = 3; // sign(priv, id | cert)
-}
-
-message ECertCRLReq {
- Identity id = 1; // admin
- Signature sig = 2; // sign(priv, id)
-}
-
-message TCertCreateReq {
- google.protobuf.Timestamp ts = 1;
- Identity id = 2; // corresponding ECert retrieved from ECA
- PublicKey pub = 3;
- Signature sig = 4; // sign(priv, ts | id | pub)
-}
-
-message TCertCreateResp {
- Cert cert = 1;
-}
-
-message TCertCreateSetReq {
- google.protobuf.Timestamp ts = 1;
- Identity id = 2; // corresponding ECert retrieved from ECA
- uint32 num = 3; // number of certs to create
- repeated TCertAttribute attributes = 4; // array with the attributes to add to each TCert.
- Signature sig = 5; // sign(priv, ts | id | attributes | num)
-}
-
-message TCertAttribute {
- string attributeName = 1;
-}
-
-message TCertCreateSetResp {
- CertSet certs = 1;
-}
-
-message TCertReadSetsReq {
- google.protobuf.Timestamp begin = 1;
- google.protobuf.Timestamp end = 2;
- Identity req = 3; // corresponding ECert retrieved from ECA
- Role role = 4; // bitmask
- Signature sig = 5; // sign(priv, begin | end | req | id | role)
-}
-
-message TCertRevokeReq {
- Identity id = 1; // user or admin whereby users can only revoke their own certs
- Cert cert = 2; // cert to revoke
- Signature sig = 3; // sign(priv, id | cert)
-}
-
-message TCertRevokeSetReq {
- Identity id = 1; // user or admin whereby users can only revoke their own certs
- google.protobuf.Timestamp ts = 2; // timestamp of cert set to revoke (0 == latest set)
- Signature sig = 3; // sign(priv, id | cert)
-}
-
-message TCertCRLReq {
- Identity id = 1; // admin
- Signature sig = 2; // sign(priv, id)
-}
-
-message TLSCertCreateReq {
- google.protobuf.Timestamp ts = 1;
- Identity id = 2;
- PublicKey pub = 3;
- Signature sig = 4; // sign(priv, ts | id | pub)
-}
-
-message TLSCertCreateResp {
- Cert cert = 1;
- Cert rootCert = 2;
-}
-
-message TLSCertReadReq {
- Identity id = 1;
-}
-
-message TLSCertRevokeReq {
- Identity id = 1; // user or admin whereby users can only revoke their own cert
- Cert cert = 2; // cert to revoke
- Signature sig = 3; // sign(priv, id | cert)
-}
-
-// Certificate issued by either the ECA or TCA.
-//
-message Cert {
- bytes cert = 1; // DER / ASN.1 encoded
-}
-
-// TCert
-//
-message TCert {
- bytes cert = 1; // DER / ASN.1 encoded
- bytes prek0 = 2; // PreK0 used to derive the keys to encrypt the TCert extensions (EnrollmentID, TCertIndex and attributes)
-}
-
-message CertSet {
- google.protobuf.Timestamp ts = 1;
- Identity id = 2;
- bytes key = 3;
- repeated TCert certs = 4;
-}
-
-message CertSets {
- repeated CertSet sets = 1;
-}
-
-message CertPair {
- bytes sign = 1; // signature certificate, DER / ASN.1 encoded
- bytes enc = 2; // encryption certificate, DER / ASN.1 encoded
-}
-
-//ACAAttrReq is sent to request an ACert (attributes certificate) to the Attribute Certificate Authority (ACA).
-message ACAAttrReq {
- // Request time
- google.protobuf.Timestamp ts = 1;
- // User identity
- Identity id = 2;
- // Enrollment certificate
- Cert eCert = 3;
- // Collection of requested attributes including the attribute name and its respective value hash.
- repeated TCertAttribute attributes = 4; // array with the pairs key/value-hash of each attribute.
- // The request is signed by the TCA.
- Signature signature = 5;
-}
-
-//ACAAttrResp is the response of Attribute Certificate Authority (ACA) to the attribute request. Is composed by the following fields:
-message ACAAttrResp {
- enum StatusCode {
- // Processed OK and all attributes included.
- FULL_SUCCESSFUL = 000;
- // Processed OK but some attributes included.
- PARTIAL_SUCCESSFUL = 001;
- // Processed OK but no attributes included.
- NO_ATTRIBUTES_FOUND = 010;
-
- // Processed with errors.
- option allow_alias = true;
- FAILURE_MINVAL = 100;
- FAILURE = 100;
- BAD_REQUEST = 200;
- // Missing parameters
- FAIL_NIL_TS = 201;
- FAIL_NIL_ID = 202;
- FAIL_NIL_ECERT = 203;
- FAIL_NIL_SIGNATURE = 204;
- FAIL_NIL_ATTRIBUTES = 205;
-
- FAILURE_MAXVAL = 205;
- }
- // Indicates the request process status.
- StatusCode status = 1;
- // Attribute certificate. Include all the attributes certificated.
- Cert cert = 2;
- // The response is signed by the ACA.
- Signature signature = 3;
-}
-
-//ACAFetchAttrReq is a request to the Attribute Certificate Authority (ACA) to refresh attributes values from the sources.
-message ACAFetchAttrReq {
- // Request timestamp
- google.protobuf.Timestamp ts = 1;
- // Enrollment certificate.
- Cert eCert = 2;
- // The request is signed by the ECA.
- Signature signature = 3;
-}
-
-//ACAFetchAttrReq is the answer of the Attribute Certificate Authority (ACA) to the refresh request.
-message ACAFetchAttrResp {
- enum StatusCode {
- // Processed OK
- SUCCESS = 000;
- // Processed with errors.
- FAILURE = 100;
- }
- // Status of the fetch process.
- StatusCode status = 1;
- // Error message.
- string Msg = 2;
-}
-
-//FetchAttrsResult is returned within the ECertCreateResp indicating the results of the fetch attributes invoked during enroll.
-message FetchAttrsResult {
- enum StatusCode {
- // Processed OK
- SUCCESS = 000;
- // Processed with errors
- FAILURE = 100;
- }
- // Status of the fetch process.
- StatusCode status = 1;
- // Error message.
- string Msg = 2;
-}
-
-//ACAAttribute is an instance of an attribute with the time constraints. Is used to marshal attributes to be stored within the certificate extensions.
-message ACAAttribute {
- // Name of the attribute.
- string attributeName = 1;
- // Value of the attribute.
- bytes attributeValue = 2;
- // The timestamp which attribute is valid from.
- google.protobuf.Timestamp validFrom = 3;
- // The timestamp which attribute is valid to.
- google.protobuf.Timestamp validTo = 4;
-}
diff --git a/hfc/lib/protos/identity.proto b/hfc/lib/protos/identity.proto
new file mode 100644
index 0000000000..dd37c474de
--- /dev/null
+++ b/hfc/lib/protos/identity.proto
@@ -0,0 +1,32 @@
+/*
+Copyright IBM Corp. 2016 All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+syntax = "proto3";
+
+option go_package = "github.com/hyperledger/fabric/msp";
+
+package msp;
+
+// This struct represents an Identity
+// (with its MSP identifier) to be used
+// to serialize it and deserialize it
+message SerializedIdentity {
+ // The identifier of the associated membership service provider
+ string Mspid = 1;
+
+ // the Identity, serialized according to the rules of its MPS
+ bytes IdBytes = 2;
+}
diff --git a/hfc/lib/utils-x509cert.js b/hfc/lib/utils-x509.js
similarity index 100%
rename from hfc/lib/utils-x509cert.js
rename to hfc/lib/utils-x509.js
diff --git a/test/unit/headless-tests.js b/test/unit/headless-tests.js
index 90228b13d8..d3155d3ea3 100644
--- a/test/unit/headless-tests.js
+++ b/test/unit/headless-tests.js
@@ -1032,13 +1032,6 @@ var TEST_KEY_PUBLIC = '04f46815aa00fe2ba2814b906aa4ef1755caf152658de8997a6a85808
var TEST_MSG_SIGNATURE_SHA2_256 = '3046022100a6460b29373fa16ee96172bfe04666140405fdef78182280545d451f08547736022100d9022fe620ceadabbef1714b894b8d6be4b74c0f9c573bd774871764f4f789c9';
var TEST_LONG_MSG_SIGNATURE_SHA2_256 = '3045022073266302d730b07499aabd0f88f12c8749a0f90144034dbc86a8cd742722ad29022100852346f93e50911008ab97afc452f83c5985a19fa3aa6d58f615c03bddaa90a1';
-var TEST_PUBLICKEY_PEM = '-----BEGIN ECDSA PUBLIC KEY-----\n' +
-'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEp53zR7+0ZkYyHw1jattcyl6S0Es9uaqc\n' +
-'lABdfMBflwZWBB8jOj+CGW3l4v+qYnAaEJl/TFG73GGtCY5/FNx9E0FkmjCtXsUY\n' +
-'tDKOY53CUoBQParnUL0mgpYkBRlguYIG\n' +
-'-----END ECDSA PUBLIC KEY-----';
-var TEST_PRIVATEKEY_PEM = '-----BEGIN PRIVATE KEY-----MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgzXIgbq9dtAzwK1yknvFTyQmZKmoLkipQHZUjfE2ILb2hRANCAASaQgfH/7XGn9mQ261INTENal0rLGzZroTK7oKHp5IAPK1nDPu+WovQwiDuaL6CzinkufHxvoeZ3XEZOonRP3qP-----END PRIVATE KEY-----';
-// var TEST_CERT_PEM = '-----BEGIN CERTIFICATE-----MIIDVDCCAvqgAwIBAgIBATAKBggqhkjOPQQDAjBOMRMwEQYDVQQKDArOoyBBY21lIENvMRkwFwYDVQQDExB0ZXN0LmV4YW1wbGUuY29tMQ8wDQYDVQQqEwZHb3BoZXIxCzAJBgNVBAYTAk5MMB4XDTE2MTIxNjIzMTAxM1oXDTE2MTIxNzAxMTAxM1owTjETMBEGA1UECgwKzqMgQWNtZSBDbzEZMBcGA1UEAxMQdGVzdC5leGFtcGxlLmNvbTEPMA0GA1UEKhMGR29waGVyMQswCQYDVQQGEwJOTDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFKnXh7hBdp6s9OJ/aadigT1z2WzBbSc7Hzb3rkaWFz4e+9alqqWg9lrur/mDYzG9dudC8jFjVa7KIh+2BxgBayjggHHMIIBwzAOBgNVHQ8BAf8EBAMCAgQwJgYDVR0lBB8wHQYIKwYBBQUHAwIGCCsGAQUFBwMBBgIqAwYDgQsBMA8GA1UdEwEB/wQFMAMBAf8wDQYDVR0OBAYEBAECAwQwDwYDVR0jBAgwBoAEAQIDBDBiBggrBgEFBQcBAQRWMFQwJgYIKwYBBQUHMAGGGmh0dHA6Ly9vY0JDQ1NQLmV4YW1wbGUuY29tMCoGCCsGAQUFBzAChh5odHRwOi8vY3J0LmV4YW1wbGUuY29tL2NhMS5jcnQwRgYDVR0RBD8wPYIQdGVzdC5leGFtcGxlLmNvbYERZ29waGVyQGdvbGFuZy5vcmeHBH8AAAGHECABSGAAACABAAAAAAAAAGgwDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4YW1wbGUuY29tMFcGA1UdHwRQME4wJaAjoCGGH2h0dHA6Ly9jcmwxLmV4YW1wbGUuY29tL2NhMS5jcmwwJaAjoCGGH2h0dHA6Ly9jcmwyLmV4YW1wbGUuY29tL2NhMS5jcmwwFgYDKgMEBA9leHRyYSBleHRlbnNpb24wCgYIKoZIzj0EAwIDSAAwRQIgcguBb6FUxO+X8DbY17gpqSGuNC4NT4BddPg1UWUxIC0CIQDNyHQAwzhw+512meXRwG92GfpzSBssDKLdwlrqiHOu5A==-----END CERTIFICATE-----';
var TEST_CERT_PEM = '-----BEGIN CERTIFICATE-----' +
'MIIDVDCCAvqgAwIBAgIBATAKBggqhkjOPQQDAjBOMRMwEQYDVQQKDArOoyBBY21l' +
'IENvMRkwFwYDVQQDExB0ZXN0LmV4YW1wbGUuY29tMQ8wDQYDVQQqEwZHb3BoZXIx' +
@@ -1066,6 +1059,7 @@ var ECDSA = jsrsa.ECDSA;
var asn1 = jsrsa.asn1;
var ecdsaKey = require('hfc/lib/impl/ecdsa/key.js');
+var api = require('hfc/lib/api.js');
test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', function (t) {
resetDefaults();
@@ -1292,7 +1286,7 @@ test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', function (t) {
testVerify(TEST_LONG_MSG_SIGNATURE_SHA2_256, TEST_LONG_MSG);
// test importKey()
- var pubKey = cryptoUtils.importKey(TEST_CERT_PEM, { algorithm: 'X509Certificate' });
+ var pubKey = cryptoUtils.importKey(TEST_CERT_PEM, { algorithm: api.CryptoAlgorithms.X509Certificate });
t.equal(pubKey.isPrivate(), false, 'Test imported public key isPrivate()');
t.equal(pubKey.getSKI(), 'b5cb4942005c4ecaa9f73a49e1936a58baf549773db213cf1e22a1db39d9dbef', 'Test imported public key SKI');
@@ -2022,6 +2016,111 @@ test('FabricCOPServices: Test _parseURL() function', function (t) {
);
});
+var Identity = require('hfc/lib/msp/identity.js');
+var MSP = require('hfc/lib/msp/msp.js');
+
+test('\n\n ** Identity class tests **\n\n', function (t) {
+ t.throws(
+ function() {
+ new Identity();
+ },
+ /Missing required parameter "id"/,
+ 'Checking required input parameters'
+ );
+
+ t.throws(
+ function() {
+ new Identity('id');
+ },
+ /Missing required parameter "certificate"/,
+ 'Checking required input parameters'
+ );
+
+ t.throws(
+ function() {
+ new Identity('id', 'cert');
+ },
+ /Missing required parameter "publicKey"/,
+ 'Checking required input parameters'
+ );
+
+ t.throws(
+ function() {
+ new Identity('id', 'cert', 'pubKey');
+ },
+ /Missing required parameter "msp"/,
+ 'Checking required input parameters'
+ );
+
+ t.throws(
+ function() {
+ var mspImpl = new MSP();
+ },
+ /Missing required parameter "config"/,
+ 'Checking required config parameter for MSP constructor'
+ );
+
+ t.throws(
+ function() {
+ var mspImpl = new MSP({signer: 'blah', admins: [], id: 'blah', cryptoSuite: 'blah'});
+ },
+ /Parameter "config" missing required field "trustedCerts"/,
+ 'Checking required config parameter "trustedCerts" for MSP constructor'
+ );
+
+ t.throws(
+ function() {
+ var mspImpl = new MSP({trustedCerts: [], admins: [], id: 'blah', cryptoSuite: 'blah'});
+ },
+ /Parameter "config" missing required field "signer"/,
+ 'Checking required config parameter "signer" for MSP constructor'
+ );
+
+ t.throws(
+ function() {
+ var mspImpl = new MSP({trustedCerts: [], signer: 'blah', id: 'blah', cryptoSuite: 'blah'});
+ },
+ /Parameter "config" missing required field "admins"/,
+ 'Checking required config parameter "admins" for MSP constructor'
+ );
+
+ t.throws(
+ function() {
+ var mspImpl = new MSP({trustedCerts: [], signer: 'blah', admins: [], cryptoSuite: 'blah'});
+ },
+ /Parameter "config" missing required field "id"/,
+ 'Checking required config parameter "id" for MSP constructor'
+ );
+
+ t.throws(
+ function() {
+ var mspImpl = new MSP({trustedCerts: [], signer: 'blah', admins: [], id: 'blah'});
+ },
+ /Parameter "config" missing required field "cryptoSuite"/,
+ 'Checking required config parameter "cryptoSuite" for MSP constructor'
+ );
+
+ var mspImpl = new MSP({
+ trustedCerts: [],
+ signer: 'blah',
+ admins: [],
+ id: 'testMSP',
+ cryptoSuite: utils.getCryptoSuite()
+ });
+
+ var cryptoUtils = utils.getCryptoSuite();
+ var pubKey = cryptoUtils.importKey(TEST_CERT_PEM, { algorithm: api.CryptoAlgorithms.X509Certificate });
+ var identity = new Identity('testIdentity', TEST_CERT_PEM, pubKey, mspImpl);
+
+ var serializedID = identity.serialize();
+ var dsID = mspImpl.deserializeIdentity(serializedID);
+ t.equal(dsID._certificate, TEST_CERT_PEM, 'Identity class function tests: deserialized certificate');
+ t.equal(dsID._publicKey.isPrivate(), false, 'Identity class function tests: deserialized public key');
+ t.equal(dsID._publicKey._key.pubKeyHex, '0452a75e1ee105da7ab3d389fda69d8a04f5cf65b305b49cec7cdbdeb91a585cf87bef5a96aa9683d96bbabfe60d8cc6f5db9d0bc8c58d56bb28887ed81c6005ac', 'Identity class function tests: deserialized public key ecparam check');
+
+ t.end();
+});
+
function getUserHome() {
return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
}