hyperledger / cacti

Hyperledger Cacti is a new approach to the blockchain interoperability problem
https://wiki.hyperledger.org/display/cactus
Apache License 2.0
338 stars 278 forks source link

proposal for fabric-secure-connector #1212

Closed Zzocker closed 3 years ago

Zzocker commented 3 years ago

Background

One question that every person designing a HL fabric based solution ask is : What the hack should I do with private key and certificates of clients? . Although fabric-sdk provide two different kind of approaches.

  1. storing client's private key and certificate together on some database (which implements wallet interface). For this approach a rough flow goes something like this

    • client send request to org's application server to invoke or query chaincode using a give KEY.
    • org's application upon receiving the request , it fetches private key and certificate corresponding to KEY.
    • uses the fetched private key to sign fabric message in order to query or invoke chaincode.
      NOTE : developer of the application has to implement authentication for client's KEY
  2. store private key in HSM , but in this approach application and HSM have to be present on same physical machine (i.e HSM should directly be connected with machine running the application). This approach is mostly used for developing client's desktop application, which will be responsible for communicating with fabric peers.

Now comes the fabric-secure-connector which only brings the advantages from both the approaches. Secure Fabric connector provides a solution to the fabric organization for managing their client's private key such that the client's private key is never brought to Node Server for singing. Currently fabric-secure-connector provide a option of keeping client's private key into Vault Transit Engine or in browser Extension (TODO).

fabric-secure-connector

Broadly this package will support two kind of identity

  1. Key stored with vault transit engine like server. (which provide cryptography as service)
  2. key stored with client's extension and signing will be done via various transport connection (ws , gRPC)

Another component , is browser extension for

NOTE : design of extension is TBD

FAQ :

  1. Can this not be implemented in cactus-plugin-ledger-connector-fabric ?
    Ans : Can be , but will lead to lot of breaking changes. developer can choose cactus-plugin-ledger-connector-fabric for the first approach and fabric-secure-connector to support multiple type of identity.

  2. Is their any use case of it ?
    Ans: currently we are trying to implement vault and ws identity for blockchain-carbon-accounting project (under hyperledger labs)

  3. Any Blockage that can be faced during the implement fabric-secure-connector? Ans : currently fabric-sdk-node support sync singing of message , here

    export interface ICryptoSuite {
         //........
    sign(key: ICryptoKey, digest: Buffer): Buffer;
    }

    but since for Identity supported by this package will require sign method to be as async , so current fabric-sdk-node cannot be directly used. To solve this I have already opened a PR to fabric-node-sdk here . In meanwhile they merge the PR and release version 2.2, I have pushed a npm package of my fork. PR merged

  4. Where can we find an implementation of it?
    Ans: https://github.com/Zzocker/blockchain-carbon-accounting/tree/secureFabric/secure-fabric . this support vault identity for now.

Thank you

@petermetz @sichen1234 @brioux @knagware9 @udosson

Below are technical details of how I am planning to implement

Top Level exported class and interface

export enum IdentityProvidersType {
     // identity by default provided by fabric-sdk-node wherein private key and certificate
     // stored together (First approach)
     Default = 'Default-X.509'

     // vault identity provider wherein private key are store with vault transit engine
     // and certificate are store in certData store
     Vault = 'Vault-X.509',

     // [ TRANSPORT ] WebSocket identity provider wherein private key are store with client inside the extension
     // signing of digest are done by sending of data as websocket message through webSocket connection between
     // server and client extension
     // certificate are store in certData store
     WebSocket = 'WS-X.509',

     // [ TRANSPORT ] gRPC identity provider wherein private key are store with client inside the extension
     // signing of digest are done by sending of data as gRPC streaming via gRPC bi-directional connection 
     // between server and client extension
     // certificate are store in certData store
     gRPC = 'gRPC-X.509',
}
// every identity  type and certificate data will extends this interface
interface IIdentity{
     // key used for storing identity data with cert datastore
     key:string
     type:IdentityProvidersType
} 
// IVaultIdentity represents a vault client.
export interface IVaultIdentity extends IIdentity{
     keyName:string
     token:string
}

// IWebsocketIdentity represents a websocket client.
// message signing will be done by back and forth message between 
// server and client over weConn
export interface IWebsocketIdentity extends IIdentity{
     wsConn:connection
}

// IGRPCIdentity represents a bi-directional gRPC client.
// message signing will be done by back and forth message between 
// server and client over biConn
export interface IGRPCIdentity extends IIdentity{
     biConn:connection
}

// IIdentityData : data that will be stored with cert datastore
// with key as client's commonName (from X509 certificate) and value as following field
interface IIdentityData extends IIdentity{
     credentials: {
          certificate: string;
          // if identity type is IdentityProvidersType.Default
          privateKey?:string;
     };
     mspId: string;
}

export interface ISecureFabricConnector{
     // array of identity types that application is going to support
     // eg [IdentityProvidersType.Vault , IdentityProvidersType.Default IdentityProvidersType.WebSocket]
     // this will accept client request with vault , default or websocket for signing fabric messages
     supportedIdentity:IdentityProvidersType[]

     // vault server config if Vault identity is support 
     vaultOptions?:{endpoint:string,transitEngineMountPath:string}

     // for registering client : NOTE /register endpoint should not be exposed to client
     // rather this endpoint is for org's admin
     registrar : {
          certificate:string
          mspId:string
          // if privateKey is provided , this private will be used for signing
          privateKey?:string

          // if provided , application will use private key of registerer stored with vault
          // to register and revoke client
          vaultKey?:{token:string,keyName:string}
     }
     // usual field required in fabric-sdk-node's GatewayOptions
    connectionProfile:object
    tlsInfo?: {
        certificate: string;
        key: string;
    };
    discovery?: DiscoveryOptions;
    eventHandlerOptions?: DefaultEventHandlerOptions;
    queryHandlerOptions?: DefaultQueryHandlerOptions;
    'connection-options'?: any;
}
export class ISecureFabricConnector{
     constructor(ISecureFabricConnector)

     /**
      * @method transact invoke/query fabric chaincode
      * @param caller client identity
      * @param channel on which chaincode is committed
      * @param ccName : fabric chaincode name
      * @param method supported by chaincode
      * @param args , method specific arguments
      */
     transact(type:'query'|'invoke',caller:IIdentity,channel:string,ccName:string,method:string,...args:string[]):Promise<Buffer>

     /**
      * @method enroll a already registered client
      * @param caller client identity
      * @param request for enrollment
      */
     enroll(caller:IIdentity,request:{enrollmentID:string,enrollmentSecret:string}):Promise<void>

     /**
      * @method rotateKey will rotate client key and store newly enrolled certificate in cert datastore
      * 
      */
     rotateKey(caller:IIdentity):Promise<void>
}
petermetz commented 3 years ago

@Zzocker This looks awesome! The only thing I'd change is to make this part of the current Fabric connector by way of introducing it as a signing credential type and it's own endpoint. That way we don't need to duplicate a lot of code between the current Fabric connector and the one being proposed here. I shall help out with the code changes!

Zzocker commented 3 years ago

@petermetz , yes you are right about creating a another plug-in for this will lead to duplication of code. But I will say, that if we implement it in existence connector, will lead to breaking changes and package version might have to upgraded to 1.x.y.

petermetz commented 3 years ago

@Zzocker Pre-1.0 breaking changes can be made between minor releases as well. In general, anything that's 0.x.x as a version is considered unstable (that's why I keep telling everyone that Cactus is not ready yet for production use). TLDR: I'm okay with breaking changes as long as we can complete them before the 1.0 release.