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']; }