• Damiano D'Amici

Setting up a third-party root Certification Authority (CA) with Hyperledger Fabric

Introduction

Hyperledger Fabric is one of the most successful projects of the Hyperledger Consortium, born within the Linux Foundation. In addition to being an excellent tool for the creation and development of distributed systems especially in the business environment, Hyperledger Fabric offers multiple configuration possibilities.

One of the very important but at the same time underestimated features is the possibility to integrate a third-party Certification Authority (CA) within the system to be developed. In this article, we will describe the steps to follow to create a system that has a third-party Root CA and an Intermediate CA that will integrate the former into the Fabric environment. This problem has already been addressed in the past, however, this article, although based on several articles, provides a working environment with the latest and newest version of Hyperledger Fabric (v 2.2).


Prerequisites

Next to all prerequisites related to Hyperledger Fabric itself, the following tools must be installed to be able to follow this tutorial:

  1. Docker

  2. Docker Compose

  3. Openssl 1.1.1d (*)

*Version 1.1.1d is not strictly necessary, but previous versions may create some problems


Getting Started

To have a working demo simply perform the following steps. First, download the repository containing the files needed for the network to work.

git clone https://github.com/ZappaBoy/fabric-mwe.git

Then enter into the repository folder.

cd fabric-mwe/external-ca/

Finally, start the initialization script.

./start.sh

The script will download all necessary components and then start the docker containers that will compose the network structure. In case of errors, check that all dependencies have been installed correctly and that there are no conflicts with other dockers. To return to a clean environment you can use the command below:

./destroy.sh.

This script removes all files, dockers, and docker volumes created by the tutorial by resetting the environment to its initial state.


Walkthrough

The initialization script performs all tasks needed to set up the tutorial example. In this section, we are going to walk through all operations performed by the script in order to analyze and explain all the operations needed for a correct setup of a third-party root CA and its supporting intermediate CA. Define some useful variables

As the network utilizes country information, as a first step we define SUBJ and CSR_NAMES variables.

export SUBJ="/C=IT/ST=Italy/L=Italy/O=org1.example.com/OU=Example/CN="
export CSR_NAMES="C=IT,ST=Italy,L=Italy,O=org1.example.com"

Hyperledger Fabric binaries downloads

As a second step, the script downloads the Hyperledger Fabric v2.2 binaries.

curl -sSL http://bit.ly/2ysbOFE | bash -s
rm -f config/configtx.yaml config/core.yaml config/orderer.yaml

These will be necessary to carry out Fabric's proprietary operations such as instantiation and installation of chaincodes, CAs interaction, and the creation of the cryptographic elements necessary for the communication of network elements.


Cryptographic elements

After downloading the Fabric binaries, the script generates the cryptographic elements for the Orderer.

export PATH=$PWD/bin:$PATH
cryptogen generate --config=./crypto-config.yaml

In order for everything to work properly, we also need to create a folder structure for the certificates and keys of the organization and its peer.

ORG_DIR=$PWD/crypto-config/peerOrganizations/org1.example.com
PEER_DIR=$ORG_DIR/peers/peer0.org1.example.com
IDENTITY_REGISTRAR_DIR=$ORG_DIR/users/admin
TLS_REGISTRAR_DIR=$ORG_DIR/users/tlsadmin
ADMIN_DIR=$ORG_DIR/users/Admin@org1.example.com
mkdir -p $ORG_DIR/ca $ORG_DIR/tlsca $ORG_DIR/msp $PEER_DIR $IDENTITY_REGISTRAR_DIR $TLS_REGISTRAR_DIR $ADMIN_DIR

Root CA Structure

Along the same lines, now we have to create a structure to store Root CA data.

mkdir -p identity-rca/private identity-rca/certs identity-rca/newcerts identity-rca/crl
touch identity-rca/index.txt identity-rca/serial
echo 1000 > identity-rca/serial
echo 1000 > identity-rca/crlnumber

And create a private key for the Root CA using the same standard used by Hyperledger Fabric (ECDSA with prime256v1 curve).

openssl ecparam -name prime256v1 -genkey -noout -out identity-rca/private/rca.identity.org1.example.com.key

We also generate a Certificate Signing Request (CSR).

openssl req -config openssl_root-identity.cnf -new -x509 -sha256 -extensions v3_ca -key identity-rca/private/rca.identity.org1.example.com.key -out identity-rca/certs/rca.identity.org1.example.com.cert -days 3650 -subj "${SUBJ}rca.identity.org1.example.com"

Similarly to the Root CA, we now create a folder structure for the Root TLS CA and key pairs.

mkdir -p tls-rca/private tls-rca/certs tls-rca/newcerts tls-rca/crl
touch tls-rca/index.txt tls-rca/serial
echo 1000 > tls-rca/serial
echo 1000 > tls-rca/crlnumber
openssl ecparam -name prime256v1 -genkey -noout -out tls-rca/private/rca.tls.org1.example.com.key
openssl req -config openssl_root-tls.cnf -new -x509 -sha256 -extensions v3_ca -key tls-rca/private/rca.tls.org1.example.com.key -out tls-rca/certs/rca.tls.org1.example.com.cert -days 3650 -subj "${SUBJ}rca.tls.org1.example.com"

Intermediate CA structure

We now move on to the creation of the necessary structure for the intermediate CA. First, we generate a private key and a Certificate Signing Request (CSR) belonging to the same organization.

openssl ecparam -name prime256v1 -genkey -noout -out $ORG_DIR/ca/ica.identity.org1.example.com.key
openssl req -new -sha256 -key $ORG_DIR/ca/ica.identity.org1.example.com.key -out $ORG_DIR/ca/ica.identity.org1.example.com.csr -subj "${SUBJ}ica.identity.org1.example.com"
openssl ca -batch -config openssl_root-identity.cnf -extensions v3_intermediate_ca -days 1825 -notext -md sha256 -in $ORG_DIR/ca/ica.identity.org1.example.com.csr -out $ORG_DIR/ca/ica.identity.org1.example.com.cert

We now create the "chain" file containing both Root CA and Intermediate CA certificates.

cat $ORG_DIR/ca/ica.identity.org1.example.com.cert $PWD/identity-rca/certs/rca.identity.org1.example.com.cert > $ORG_DIR/ca/chain.identity.org1.example.com.cert

Finally, as for the TLS Root CA, we generate the structure for the Intermediate TLS CA.

openssl ecparam -name prime256v1 -genkey -noout -out $ORG_DIR/tlsca/ica.tls.org1.example.com.key
openssl req -new -sha256 -key $ORG_DIR/tlsca/ica.tls.org1.example.com.key -out $ORG_DIR/tlsca/ica.tls.org1.example.com.csr -subj "${SUBJ}ica.tls.org1.example.com"
openssl ca -batch -config openssl_root-tls.cnf -extensions v3_intermediate_ca -days 1825 -notext -md sha256 -in $ORG_DIR/tlsca/ica.tls.org1.example.com.csr -out $ORG_DIR/tlsca/ica.tls.org1.example.com.cert
cat $ORG_DIR/tlsca/ica.tls.org1.example.com.cert $PWD/tls-rca/certs/rca.tls.org1.example.com.cert > $ORG_DIR/tlsca/chain.tls.org1.example.com.cert

Starting the network via docker

It is now time to start the network. First, we start the Intermediate CA and make sure the container is working and responding correctly

docker-compose up -d ica.org1.example.com
curl http://localhost:7054/cainfo\?ca\=ca
curl http://localhost:7054/cainfo\?ca\=tlsca

Before continuing, wait about a minute to make sure the network finishes its setup. After that, we proceed by creating an identity for the Admin and a user.

export FABRIC_CA_CLIENT_HOME=$IDENTITY_REGISTRAR_DIR
fabric-ca-client enroll --caname ca --csr.names "${CSR_NAMES}" -m admin -u http://admin:adminpw@localhost:7054
fabric-ca-client register --caname ca --id.name Admin@org1.example.com --id.secret adminpw --id.type admin --id.affiliation org1 -u http://localhost:7054
fabric-ca-client register --caname ca --id.name peer0.org1.example.com --id.secret mysecret --id.type peer --id.affiliation org1 -u http://localhost:7054
export FABRIC_CA_CLIENT_HOME=$ADMIN_DIR
fabric-ca-client enroll --caname ca --csr.names "${CSR_NAMES}" -m Admin@org1.example.com -u http://Admin@org1.example.com:adminpw@localhost:7054
cp $ORG_DIR/ca/chain.identity.org1.example.com.cert $ADMIN_DIR/msp/chain.cert
cp $PWD/nodeou.yaml $ADMIN_DIR/msp/config.yaml
export FABRIC_CA_CLIENT_HOME=$PEER_DIR
fabric-ca-client enroll --caname ca --csr.names "${CSR_NAMES}" -m peer0.org1.example.com -u http://peer0.org1.example.com:mysecret@localhost:7054
cp $ORG_DIR/ca/chain.identity.org1.example.com.cert $PEER_DIR/msp/chain.cert
cp $PWD/nodeou.yaml $PEER_DIR/msp/config.yaml

We then generate the certificates and key pairs to use the TLS connection between the network elements.

export FABRIC_CA_CLIENT_HOME=$TLS_REGISTRAR_DIR
fabric-ca-client enroll --caname tlsca --csr.names "${CSR_NAMES}" -m admin -u http://admin:adminpw@localhost:7054
fabric-ca-client register --caname tlsca --id.name peer0.org1.example.com --id.secret mysecret --id.type peer --id.affiliation org1 -u http://localhost:7054
export FABRIC_CA_CLIENT_HOME=$PEER_DIR/tls
fabric-ca-client enroll --caname tlsca --csr.names "${CSR_NAMES}" -m peer0.org1.example.com -u http://peer0.org1.example.com:mysecret@localhost:7054
cp $PEER_DIR/tls/msp/signcerts/*.pem $PEER_DIR/tls/server.crt
cp $PEER_DIR/tls/msp/keystore/* $PEER_DIR/tls/server.key
cat $PEER_DIR/tls/msp/intermediatecerts/*.pem $PEER_DIR/tls/msp/cacerts/*.pem > $PEER_DIR/tls/ca.crt
rm -rf $PEER_DIR/tls/msp $PEER_DIR/tls/*.yaml

By now it should already be clear that certificates can indeed be created via a third-party Root CA within a Hyperledger Fabric network with the help of an Intermediate CA. With the following steps, we create a channel and utilize a sample chaincode to make sure the network is working properly. To do so, we first prepare a structure for Membership Service Providers (MSP).

mkdir -p $ORG_DIR/msp/admincerts $ORG_DIR/msp/intermediatecerts $ORG_DIR/msp/cacerts $ORG_DIR/msp/tlscacerts $ORG_DIR/msp/tlsintermediatecerts
cp $PEER_DIR/msp/cacerts/*.pem $ORG_DIR/msp/cacerts/
cp $PEER_DIR/msp/intermediatecerts/*.pem $ORG_DIR/msp/intermediatecerts/
cp $PWD/tls-rca/certs/rca.tls.org1.example.com.cert $ORG_DIR/msp/tlscacerts/
cp $ORG_DIR/tlsca/ica.tls.org1.example.com.cert $ORG_DIR/msp/tlsintermediatecerts/
cp $ORG_DIR/ca/chain.identity.org1.example.com.cert $ORG_DIR/msp/chain.cert
cp $PWD/nodeou.yaml $ORG_DIR/msp/config.yaml

After that, it is time to create a genesis block and a channel.

export FABRIC_CFG_PATH=${PWD}
configtxgen -profile OrdererGenesis -outputBlock ./config/genesis.block -channelID genesis-channel
configtxgen -profile Channel -outputCreateChannelTx ./config/${CHANNELID}.tx -channelID ${CHANNELID}

We are now ready to start the Orderer, peer, and CLI dockers.

docker-compose up -d orderer.example.com peer0.org1.example.com cli

Now it is time to create the channel's artifacts and connect it to the network. To do so, we also define an ID for the channel.

export CHANNELID=”MYCHANNELID”
docker exec cli peer channel create -o orderer.example.com:7050 --tls --cafile /var/crypto/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem -c ${CHANNELID} -f /config/${CHANNELID}.tx
docker exec cli peer channel join -b ${CHANNELID}.block

For testing the network, we install one of the sample chaincodes provided by Hyperledger Fabric for such purpose, the "marbles" chaincode.

docker exec cli peer chaincode install -n marbles -v 1.0 -l node -p /opt/gopath/src/github.com/marbles02/node -v 1.0
docker exec cli peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile /var/crypto/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C ${CHANNELID} -n marbles -l "node" -v 1.0 -c '{"Args":["init"]}' -P "OR('Org1MSP.member')"

Such chaincode will be used to test the network by manipulating the two marbles variables and then checking for their correct value.

docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /var/crypto/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C ${CHANNELID} -n marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}' --waitForEvent
docker exec cli peer chaincode query -C ${CHANNELID} -n marbles -c '{"Args":["readMarble","marble2"]}'

If everything went well, the values shown by the second command should match the ones entered in the first command. We have therefore demonstrated that it is possible to integrate a Certification Authority within the Hyperledger Fabric structure.

Credits

A special thanks goes to Federico Zappone who authored the tutorial repo and helped to redact most of this article. Secondly, as most of this tutorial has been realized drawing from a tutorial for previous Fabric versions shared for free online by Aldred Benedict, Federico and I would like to thank him for his great contributions.