The certificates and keys generated when you enroll an identity with a network are the underpinning of Hyperledger Fabric’s permissioned blockchain. These certificates and keys need to be stored somewhere for applications to access them for signing transactions. This tutorial details the process, code, and document structures required to store and retrieve them from an IBM Cloudant® database using the Fabric Node SDK’s built-in CouchDBKeyValueStore.

Hyperledger Fabric differs from other blockchain implementations in that it is private and permissioned. Instead of a publicly accessible and permission-less system where protocols like proof of work can be used (such as Bitcoin), Fabric uses the notion of enrolling identities through a trusted Membership Service Provider (MSP). The artifacts created through this enrollment process are used for signing transactions submitted to the network. These signatures are then verified through the participating certificate authorities.

Note: I will not go into the details of identities and MSPs; the assumption here is that you have a basic understand of the concepts.

Any application that is required to submit transactions for a user, such as a Node.js web application, needs access to the keys for that user. There are several options available for storing these keys for retrieval by the app. In this tutorial, I will describe the steps you need to take in order to store certificates and keys in an IBM Cloudant database, and subsequently configure the Fabric Node SDK to use the database as the store for those artifacts.

IBM Cloudant is a NoSQL JSON document database based on the open source CouchDB project. Given the fact that the public-private key implementation relies entirely on these keys not being compromised, keeping them safe is a top priority. IBM Cloudant has many strengths when being considered as a key store, including:

  • All documents are fully encrypted.
  • Databases are managed by access controls, meaning unauthorised users cannot see the data.
  • It has built-in backup and disaster recovery functionality.

Prerequisites

To complete the steps in this tutorial, you need:

  • Hyperledger Fabric 1.2 or later
  • The Fabric binaries installed as described in the documentation for the relevant version
  • A running Fabric network, which can be an IBM Blockchain Platform network, a multi-host Docker network, or a single-host Docker network such as BYFN in the Fabric tutorials

Estimated time

Completing this tutorial should take 30-60 minutes.

Step 1. User registration and enrollment

Before you can store any certificates or keys, you need to generate them. You do this by registering and enrolling an identity with a certificate authority within the Fabric network. To do this, you use the fabric-ca-client command. In their simplest form, the commands to register and enroll an identity are as follows:

fabric-ca-client register --id.name test -u http://<url>:<port>

fabric-ca-client enroll -u http://test:<password>@<url>:<port> -M /home/test

…where <url> and <port> are the address of the certificate authority the user wishes to use for registration and enrollment.

Note: Unless explicitly passed in as an option, the register command returns the identity’s enroll password to be used in the enroll command.

There are many layers of complexity that can be added to these commands, particularly when registering (for example, assigning affiliations or attributes to an identity), but that is outside the scope of this tutorial. For more details, see Registering a new identity and Enrolling a peer identity.

Step 2. Create the CouchDB documents

Now that you’ve obtained the crypto material by enrolling the identity, you can go ahead and store them in the relevant places. First, create two databases in your Cloudant instance on IBM Cloud, stateStore and cryptoStore, to be used for their respective purposes.

State store for certificates

The state store is used to store the certificates for any enrolled identity that the application needs to use. This is most likely to consist of identities created for end users, although it may differ in your use case and architecture. To complete this step, you need the following information from your MSP root /home/test:

  1. The name of the file found in the keystore directory with “_sk” removed from the end; you will use this as <PRIVATE_KEY_NAME> later
  2. The contents of the cert.pem file found in the signcerts directory; you will use this as <SIGN_CERT> later

For each relevant identity, you need to create a document in the stateStore database that takes the following structure:

{
  "_id": "test",
  "member": "<STRINGIFIED_ESCAPED_JSON>"
}

where <STRINGIFIED_ESCAPED_JSON> is replaced with the stringified and escaped result of the following:

{
    "name":"test",
    "mspid":"org1",
    "roles":null,
    "affiliation":"",
    "enrollmentSecret":"<ENROLLMENT_SECRET>",
    "enrollment": {
        "signingIdentity":"<PRIVATE_KEY_NAME>",
        "identity": {
            "certificate":"<SIGN_CERT>"
        }
    }
}

where <ENROLLMENT_SECRET> is the password previously passed in to fabric-ca-client enroll. Note that <SIGN_CERT> needs to be escaped so that new lines are replaced with \n.

Note: You may also have a different value for mspid as well as some roles/affiliations set.

Crypto store for keys

The crypto store is used to store the private keys for each identity. In order to add these keys to your IBM Cloudant database, you’ll need the following pieces of information:

  1. The name of the file found in the /home/test/keystore directory with “_sk” removed from the end; you will use this as <PRIVATE_KEY_NAME> later
  2. The contents of the file found in the home/test/keystore directory; you will use this as <PRIVATE_KEY> later

For each identity, you need to create a document in the cryptoStore database that takes the following structure:

{
  "_id": "<PRIVATE_KEY_NAME>-priv",
  "member": "<PRIVATE_KEY>"
}

As before, <PRIVATE_KEY> needs to be escaped so that new lines are replaced with \n.

At this point, you can remove the crypto material from the MSP as you have imported it into your database and there is no need to store copies.

Step 3. Configure the Node.js app

Now that you have successfully registered and enrolled your identity/identities and added the crypto material to your database, you are ready to configure your Node.js application to use them as your stores.

First, you need to import the CouchDBKeyValueStore, which is supplied with the Fabric Node SDK:

const CDBKVS = require('fabric-client/lib/impl/CouchDBKeyValueStore.js');

State store

For the state store, create a new instance of this class, providing it with the username, password, and URL to access the IBM Cloudant instance, and the name of the database you wish to use within that instance:

let stateStore = await new CDBKVS({url: 'https://<USERNAME>:<PASSWORD>@<URL>', name: '<DB_NAME>'})

Then you just need to set this instance of the CouchDBKeyValueStore as the state store for your Fabric client:

this.client.setStateStore(stateStore);

Crypto store

The steps for the crypto store are similar to those of the state store, although the crypto key store itself is actually set on a crypto suite, which is in turn set for your Fabric client. You should now create a new crypto suite to be used:

const cryptoSuite = FabricClient.newCryptoSuite();

Next, set the crypto key store on this suite to be an instance of the CouchDBKeyValueStore using the username, password, URL, and database name as you did with the state store:

cryptoSuite.setCryptoKeyStore(FabricClient.newCryptoKeyStore(CDBKVS, {
    url: 'https://<USERNAME>:<PASSWORD>@<URL>.cloudant.com',
    name: '<DB_NAME>'
}));

Finally, set this configured crypto suite on your instance of the Fabric client:

this.client.setCryptoSuite(cryptoSuite);

Once you’ve completed this configuration, you can set the user context on the client instance using getUserContext() prior to submitting any transactions to your network.

Summary

That’s it! You now know how to store the key and certificate for your enrolled identity in an IBM Cloudant database and retrieve them in order to set the user context of a Fabric client instance.

As I mentioned, there are many factors you need to consider when deciding what type of storage is appropriate for the crypto material. For example, financial regulations might require a hardware security module, and different measures may be necessary for administrator keys given the added permissions they have. A discussion around those considerations is out of scope here, but suffice it to say the approach detailed in this tutorial is not necessarily applicable to all use cases.