Introduction
Fabric CA Server provides flexibility when bringing up a Certificate Authority (CA). If we are doing testing or just a small setup, we may let the Fabric CA Server generate CA material by itself. In real life we are more likely given an Intermediate CA (ICA) from an existing enterprise CA (which is the Root CA and source of trust). In this case, we are using the given ICA issuing certificate for entities of our organization in the fabric network.
Here in this article the two setups of Fabric CA Server are demonstrated. We use Test Network as it by default has the first setup (self-generated Root CA) when the proper option is flagged. In the second setup, we will generate an ICA outside and use this ICA in Fabric CA Server. In these two setups, we can use the scripts provided by Test Network. We first make observations on the first setup, and see how we can tune the configuration and script to support the second setup. We can see in both setups, with crypto material being properly generated, the fabric network is working well.
For those new to Test Network, you can check the readthedoc here, or refer to this article.
This setup is using Fabric v2.0.
Quick Introduction to Fabric CA Server
Overview
Fabric CA Server is the CA software provided by Hyperledger Fabric. It is important to distinguish a CA from a CA software or tool.
When we talk about a CA, we are referring to a party or an organization (not in the Fabric sense!), who is issuing certificates to entities. Anyone when presented with any issued certificates can verify them based on some CA’s known information (concretely, CA’s certificate) without direct interaction with the CA.
Each CA is characterized by two components
- a private key, which the CA keeps it secret. This is the key generating signature on certificates (signing certificate) which are issued to others.
- a certificate (CA Cert), which is made public. Inside the CA Cert there is the CA’s subject, public key and a signature.
How is this certificate signing and issuance done? It is by means of a CA software or tool. A common one is openssl. Technically, as far as one gets holding both the private key and CA Cert, one can use openssl to issue certificates to entities, acting as this CA.
Putting it back to the context of Hyperledger Fabric, as fabric networks have some specific requirements on MSP directory structure, there will be a lot of manual process if we use openssl. Here Fabric CA Server provides a better choice.
As a result, make sure we see Fabric CA Server as a CA software or tool, not the CA itself. We can only say a Fabric CA Server a CA when a private key and a CA certificate are well incorporated into Fabric CA Server.
Possible Setups of Fabric CA Server
When we bring up a Fabric CA Server, there are several possible setups.
When no CA material is given (setup A in the diagram), Fabric CA Server generates a Root CA, which contains a private key and a self-signed certificate (CA Cert). Once this private key and CA Cert is there, this Fabric CA Server can act as a CA, issuing certificate to entities. This is the setup of Test Network. We will see it in the first part of the demonstration.
When a CA material, that is, a private key and a CA Cert is given (setup B and C in the diagram), this CA material is configured in the Fabric CA Server, and now the Fabric CA Server assumes the CA role based on the CA material. In this case, no new Root CA is generated. The Fabric CA Server is issuing certificates with the given CA material.
In this setup, the given CA certificate can be a Root CA (setup B in the diagram) or an Intermediate CA (setup C in the diagram). If it is a Root CA, again, it is a self-signed certificate and the trust is tied to the CA itself. It is a more common case that the given CA is an Intermediate CA, which has a “parent” CA having issued and signed this Intermediate CA. The parent CA can be a Root CA or another Intermediate CA. The chain of certificates is the given CA certificate and all its parent certificates up to a Root CA.
Chain of Certificates in Fabric CA Server
Chain of certificates (setup B and C in diagram above) are shown in the diagram below, with zero or more than one ICAs. Note that both RCA or ICA are CAs, able to issue certificates. Our trust is always back to a Root CA, but using ICA does not reduce the trust level. For example, for the top of the diagram we trust the issued certificates because they are issued by a Root CA. For the others, where ICAs are in the picture, we accept the certificates issued by ICA because we can trace the ICA back to a Root CA. We cannot say which setups are better than others, as in most cases the setup depends on the real business situations.
In our demonstration, we are showing the middle one, in which an RCA and an ICA are generated externally, and the ICA and the chain of certificates is installed and configured in a Fabric CA Server. We later use this Fabric CA Server to issue certificates to an organization (Org1).
Demonstration
1. Observing Test Network
The script network.sh
provided in Test Network comes with an option -ca
, which generates crypto material using Fabric CA Server (the other option is using cryptogen with standard and less flexible use). When this option is selected, three Fabric CA Servers, one for each organization, are being brought up. All crypto material for the whole network is generated directly in these Fabric CA Servers. The original script design Root CAs are generated by each Fabric-CA Server (setup A in the diagram shown above), which means that the CA certificate is a self-signed certificate (subject = issuer). We will make observations over the CA for Org1, and all the material issued by this CA.
1.1 Bring Up CA Servers and all network components
cd test-network
./network.sh up -ca
1.2 Observe CA of Org1
We go into the ca_org1 container and take a look at the certificates of our interests.
docker exec -it ca_org1 bash
cd /etc/hyperledger/fabric-ca-server
ls -l
We see two certificates: ca-cert.pem
and tls-cert.pem
. The corresponding private keys are kept in msp/keystore/
, which is beyond our interests in this article.
Next we check the subject and issuer of these two certificates.
We see that ca-cert.pem
is a self-signed certificate, meaning that this CA is a Root CA (subject = issuer). Meanwhile the tls-cert.pem
is a certificate issued by the Root CA. This certificate is purely for TLS communication to this Root CA, and we will not cover this.
1.3 Observe Certificates of Org1 Entities
In Test Network we have one peer (peer0) and two users (Admin and User1). Peer comes with both identity (MSP) and TLS, while users only have MSP.
Here are the subject and issuer for each entity. We can see all of them are issued by the Root CA.
Here is how ca_org1 is working in the Test Network.
1.4 Test with Channel Creation and Chaincode Deployment
For sake of completeness, we create the channel and deploy sample Fabcar chaincode and see things are working well. We do the same after our modification.
./network.sh up createChannel
./network.sh up deployCC
If everything works fine, we will see a dump of car records when the script is completely executed.
1.5 Clean Up
Shutdown Test Network and remove the directories for our next setup.
./network.sh down
In case there are permission error messages
sudo rm -r organizations/fabric-ca/ordererOrg/msp
sudo rm -r organizations/fabric-ca/org1/msp
sudo rm -r organizations/fabric-ca/org2/msp
2. Prepare Intermediate Certificate Authority (ICA) for Org1
In the previous setup (original Test Network), an RCA is generated in Fabric CA Server, and it issues certificates to the organization entities.
RCA (ca.org1.example.com
) ⇒ certificates for entities
Now our goal is to prepare an RCA and an ICA outside. Later the ICA and the chain of certificates are configured in Fabric CA Server. Then we let the Fabric CA Server issue certificates to the organization entities.
RCA (ca.org1.example.com
) ⇒ ICA (ica.org1.example.com
) ⇒ certificates for entities
We are using openssl to generate the RCA and ICA. The method is based on Aldred Benedict’s article.
2.1 Prepare openssl configuration
cd /tmp mkdir gen-ica cd gen-icatouch index.txt serialecho 1000 > serial echo 1000 > crlnumber
and place ca.cnf
into gen-ica/
.
# OpenSSL root CA configuration file. # Copy to `/root/ca/openssl.cnf`. [ ca ] # `man ca` default_ca = CA_default [ CA_default ] # Directory and file locations. dir = . certs = $dir crl_dir = $dir new_certs_dir = $dir database = $dir/index.txt serial = $dir/serial RANDFILE = $dir/.rand # The root key and root certificate. private_key = $dir/rca.key certificate = $dir/rca.cert # For certificate revocation lists. crlnumber = $dir/crlnumber crl = $dir/rca.crl crl_extensions = crl_ext default_crl_days = 30 # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha512 name_opt = ca_default cert_opt = ca_default default_days = 375 preserve = no policy = policy_strict [ policy_strict ] # The root CA should only sign intermediate certificates that match. # See the POLICY FORMAT section of `man ca`. countryName = match stateOrProvinceName = match organizationName = match localityName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_loose ] # Allow the intermediate CA to sign a more diverse range of certificates. # See the POLICY FORMAT section of the `ca` man page. countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] # Options for the `req` tool (`man req`). default_bits = 4096 distinguished_name = req_distinguished_name string_mask = utf8only # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha512 # Extension to add when the -x509 option is used. x509_extensions = v3_ca [ req_distinguished_name ] countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name localityName = Locality Name 0.organizationName = Organization Name organizationalUnitName = Organizational Unit Name commonName = Common Name emailAddress = Email Address # Optionally, specify some defaults. #countryName_default = [2 letter contry code] #stateOrProvinceName_default = [State or Province] #localityName_default = [City or Town] #0.organizationName_default = [Name of the organization] #organizationalUnitName_default = [Unit] #emailAddress_default = [your email address] [ v3_ca ] # Extensions for a typical CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ v3_intermediate_ca ] # Extensions for a typical intermediate CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ usr_cert ] # Extensions for client certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection [ server_cert ] # Extensions for server certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth [ crl_ext ] # Extension for CRLs (`man x509v3_config`). authorityKeyIdentifier=keyid:always [ ocsp ] # Extension for OCSP signing certificates (`man ocsp`). basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, digitalSignature extendedKeyUsage = critical, OCSPSigning
2.2 Generate self-signed Root CA
This involves two steps:
- generate a private key for RCA
- generate a self-signed certificate from the private key based on the configuration.
openssl ecparam -name prime256v1 -genkey -noout -out rca.keyopenssl req -config ca.cnf -new -x509 -sha256 -extensions v3_ca -key rca.key -out rca.cert -days 3650 -subj "/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com"
2.3 Generate ICA issued by Root CA
This involves three steps:
- generate a private key for ICA
- generate a CSR based on this ICA with proper information
- RCA issues certificate to ICA based on the CSR
openssl ecparam -name prime256v1 -genkey -noout -out ica.keyopenssl req -new -sha256 -key ica.key -out ica.csr -subj "/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ica.org1.example.com"openssl ca -batch -config ca.cnf -extensions v3_intermediate_ca -days 365 -notext -md sha256 -in ica.csr -out ica.cert
2.4 Prepare chain of certificates
cat ica.cert rca.cert > chain.cert
The following files will be later incorporated into Fabric CA Server
- ICA private key:
ica.key
- ICA certificate:
ica.cert
- Chain of certificate:
chain.cert
And we will not work on the Root CA any more. The CA is represented by ica.key
and ica.cert
, with the chain of certificates showing the parent certificate(s) up to a root certificate.
This is what we have generated: an ICA, which will be configured in Fabric CA Server in next step.
3. Create a New Test Network with ICA for Org1
To leverage as much as possible on Test Network setup and scripts, we simply copy the whole Test Network into another network, to a directory test-network-ica/
. We then modify some parts of configuration in order to use the ICA for Org1.
3.1 Create Working Directory
We simply copy the whole test-network/
directory to test-network-ica/
.
cd fabric-samples
cp -r test-network test-network-ica
cd test-network-ica
Copy the three files we create before to the directory that will be mapped to our ca_org1 container.
cp /tmp/gen-ca/ica.key organizations/fabric-ca/org1/
cp /tmp/gen-ca/ica.cert organizations/fabric-ca/org1/
cp /tmp/gen-ca/chain.cert organizations/fabric-ca/org1/
For our reference, here is the ca_org1 container defined in docker/docker-compose-ca.yaml
. We see the directory of organizations/fabric-ca/org1
is mapped to /etc/hyperledger/fabric-ca-server/.
We will refer to these files in the configuration file in next step.
3.2 Modify Configuration File
The only file we need to update is organizations/fabric-ca/org1/fabric-ca-server-config.yaml
. In the ca
portion we see empty on keyfile
, certfile
and chainfile
. With this setup, Fabric CA Server will generate an RCA with self-signed certificate, which is what we observe in the Test Network demonstration.
Now we update this file with the correct path. Remember, we are referring to the directory in the container, not in my localhost.
Make sure this file is modified before the ca_org1 container is up and running. The ca_org1 will refer to this file when bringing up the CA.
3.3 Modify the Script
In theory the configuration is complete. We can bring up CA containers, perform all the entity registration and enrollment, one by one, and construct the required directories needed in MSP and TLS.
To make life easier, we modify the existing scripts in order to make it more automated. (Note that we first make modifications to the script. We will observe the MSP directory later and understand better why we make such modifications.)
The script we are going to modify is the function createOrg1 in organizations/fabric-ca/registerEnroll.sh
. Concretely, we change the reference to cacerts/
and tlscacerts/
to
cacerts/
⇒intermediatecerts/
tlscacerts/
⇒tlsintermediatecerts/
Currently
Now change to
Currently
Now change to
3.4 Bring Up Fabric CA Servers and all network components
cd test-network
./network.sh up -ca
3.5 Observe CA of Org1
We go into the ca_org1 container and take a look at the certificates of our interests.
docker exec -it ca_org1 bash
cd /etc/hyperledger/fabric-ca-server
ls -l
We do not see ca-cert.pem
any more. The only certificate we see is tls-cert.pem
, which is the TLS server certificate. We can inspect this TLS server certificate.
We see this TLS server certificate is issued by ICA, which we generated outside Fabric CA Server. It shows this CA is running.
3.6 Observe Certificates of Org1 Entities
Here are the subject and issuer for each entity. We can see all of them are issued by the ICA.
3.7 Observe the Directory Structure of an Entity
Here we take the peer as an example. Inspect peer0.org1.example.com/msp
and take a look at the result after enrollment.
We see two directories about CA certificates now: cacerts/
and intermediatecerts/
We get back the RCA-ICA we generated using openssl in Step 2. And as certificates are issued to entities by ICA, you now understand why we modify the script to change cacerts/
to intermediatecerts/
and similar in tls as well in step 3.3.
Here is how ca_org1 is working in our modified Test Network.
3.8 Test with Channel Creation and Chaincode Deployment
./network.sh up createChannel
./network.sh up deployCC
If everything works fine, we will see a dump of car records when the scripti is completely executed.
3.9 Clean Up
Shutdown Test Network and remove the directories for our next setup.
./network.sh down
In case there are permission error messages
sudo rm -r organizations/fabric-ca/ordererOrg/msp
sudo rm -r organizations/fabric-ca/org1/msp
sudo rm -r organizations/fabric-ca/org2/msp
Summary
In this article we observe the two different setups of Fabric CA Server: one is using an RCA self generated by Fabric CA Server (original Test Network setup), and one is using an ICA generated outside and let the Fabric CA Server issue certificates with this ICA (our modified Test Network setup). The former is good for tests or very small setup, while the latter is more realistic as enterprises may have their own CA infrastructure and we are given an ICA for our fabric network.
Special thanks to Aldred Benedict on the work how to generate RCA and ICA using openssl. This makes our demonstration much easier.