Tessera SSL Configuration for P2P Communication
By: Maneesh Grover, Rakesh Kumar Chinubhai Lunagariya, and Tejas Pradeep Borawake
Tessera is a transaction manager in the Quorum blockchain network, which allows private transactions in Quorum. Tessera transaction managers secure communication between peers through a two-way SSL configuration. The developer community lacks documentation and tutorials on the steps to create certificates, key-stores, and trust-stores and using them in Tessera configuration files. In addition, considerable effort is required trying different combinations of configurations to arrive at a working setup.
This blog walks through the steps for using self-signed certificate or third-party Certificate Authority (CA) certificates for configuring Tessera-to-Tessera communication by enabling the TLS option in the configuration file.
This blog is divided into two parts:
Part I— Errors and exceptions encountered while creating and using self-signed certificates, and Quorum private transaction flow.
Part II— A practical guide for configuring Tessera SSL P2P communication using self-signed certificates.
The first part discusses problems that developers encounter while creating certificates that can be used for server/client communication. These problems arise due to incomplete or improper information provided in the configuration file while generating certificates.
The second part provides step-by-step information and commands on generating self-signed Certificate Authority (CA) certificates, server/client private keys, key stores, and trust stores. Next, it shows how to use generated artifacts when configuring Quorum Tessera nodes for secure communications using SSL.
Part I: Error/Exception and Tessera Private Transaction Flow
Errors/exceptions encountered during certificate creation:
- SSLHandshakeException.
Failed to connect to node https://IP:9001/, due to javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target - No subject alternative names (SAN) present
Failed to connect to node https://IP:9001/, due to javax.net.ssl.SSLHandshakeException: No subject alternative names(SAN) present - How to validate the certificate is proper.
Quorum Tessera (Transaction Manager): The transaction manager performs the following operations:
- Peer-to-peer network creation with other transaction managers.
- Delegation of key management and payload encryption/decryption to the enclave.
- Data handling by using external databases for transaction handling.
- Managing private transaction payload and ensuring their delivery to other privacy-enabled Quorum nodes that are part of the transaction.
Quorum Private Transaction Flow: Quorum leverages Tessera to enable networks to transact with some or all parties confidentially. Tessera is a stateless JAVA system used to enable encryption, decryption, and communication of private transactions in Quorum.
Part II: TLS Configuration and Self-Signed CA and Certificates
TLS communication configuration between two Tessera nodes:
There are three modes in which Tessera can become TLS-enabled. They are:
- CA: CA mode involves certificate creation by the CA and accepting the chain certificate into other nodes.
- Tofu (Trust On First Use): At the first use, this mode creates known-client and known-server files along with their certificate signatures.
- Whitelist: Only whitelisted nodes are allowed to connect with each Tessera TM.
To have SSL mode enabled for Tessera P2P communication, we first need to create primary certificates, chain certificates, key-stores, and trust-stores and provide details in the configuration files for running nodes. Parts A to C below shows how to create self-signed CA certificates and the rest of the required certificates, etc. and Part D shows how to utilize these certificates in each of these modes.
A. Self-Signed Certificate Authority:
First, to create a self-signed Certificate Authority (CA), open the configuration file outlined as in ‘san_ca.cnf’ is required, and then execute the OpenSSL command for generating the CA certificate and CA private key.
- CA Certificate Configuration File:
2. Openssl command:
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout wipnode1-ca-key.pem -out wipnode1-ca-cert.pem -config san_ca.cnf
B. Server-Side Certificate and TrustStore Generation:
- Server Certificate Request (CSR) Creation: Open the proper configuration file for Server Certificate, as shown in ‘san_server.cnf’, and execute the OpenSSL command, which will generate a private key file and request for a certificate for the server as shown below:
→OpenSSL req -newkey rsa:2048 -nodes -days 3650 -keyout wipnode1-server-key.pem -out wipnode1-server-req.pem -config san_server.cnf
2. Server Certificate Creation:
In the openssl command below, provide the CA Certificate and Key generated in Step A above and server configuration file:
→openssl x509 -req -days 3650 -set_serial 01 -in wipnode1-server-req.pem -out wipnode1-server-cert.pem -CA wipnode1-ca-cert.pem -CAkey wipnode1-ca-key.pem -extfile san_server.cnf -extensions v3_ca
3. Server Chain Certificate Creation: The chain certificate is created to be shared with other parties for TLS. The chain certificate contains all certificates in sequence from CA => Intermediary Certificates => Server/Client Certificate. Command to have chain certificate as below:
→cat wipnode1-ca-cert.pem wipnode1-server-cert.pem > wipnode1-server-chain.pem
4. Server KeyStore Creation:
→Generate .pk12 file by running below openssl command:
openssl pkcs12 -export -in wipnode1-server-chain.pem -inkey wipnode1-server-key.pem -out wipnode1server.p12 -name “wipnode1server”
→Create KeyStore for server by running command:
<Path_to_JAVA_JDK_Installation>/bin/keytool -importkeystore -destkeystore wipnode1-server-keystore.jks -deststorepass password -srckeystore wipnode1server.p12 -srcstoretype PKCS12 -srcstorepass password
5. Server TrustStore Creation:
<Path_to_JAVA_JDK_Installation>/bin/keytool -import -file wipnode1-server-chain.pem -keystore wipnode1-server-truststore.jks -storepass password
C. Client-Side Certificate and Trust Store Certification
- Client Certificate Request (CSR) Creation: Open the proper configuration file for Client Certificate as shown in ‘san_client.cnf’ and execute the shown OpenSSL command, which will generate a private key file and request for a certificate for the client:
→OpenSSL req -newkey rsa:2048 -nodes -days 3650 -keyout wipnode1-client-key.pem -out wipnode1-client-req.pem -config san-client.cnf
2. Client Certificate Creation:
In the openssl command below, provide CA Certificate and Key generated in Step A above and client configuration file:
→ openssl x509 -req -days 3650 -set_serial 01 -in wipnode1-client-req.pem -out wipnode1-client-cert.pem -CA wipnode1-ca-cert.pem -CAkey wipnode1-ca-key.pem -extfile san-client.cnf -extensions v3_ca
3. Client Chain Certificate Creation:
→ cat wipronode1-ca-cert.pem wipronode1-client-cert.pem > wipronode1-client-chain.pem
4. Client Key Store Creation:
→Generate .pk12 file by running command:
openssl pkcs12 -export -in wipnode1-client-chain.pem -inkey wipnode1-client-key.pem -out wipnode1client.p12 -name “wipnode1client”
→Create KeyStore for client by running command:
<Path_to_JAVA_JDK_Installation>/bin/keytool -importkeystore -destkeystore wipnode1-client-keystore.jks -deststorepass password -srckeystore wipnode1client.p12 -srcstoretype PKCS12 -srcstorepass password
5. Client Trust Store Creation:
Path_to_JAVA_JDK_Installation>/bin/keytool -import -file wipnode1-client-chain.pem -keystore wipnode1-client-truststore.jks -storepass password
The steps below need to be performed for all server and client nodes that are part of the network:
- Repeat steps A to C to create certificates and trust-stores for other nodes.
- Update hosts file to include server and client DNS names.
- Once all certificate and trust-stores are generated, import each other’s chain certificates:
- Server chain certificates should be imported into each other’s server’s trust-stores and client chain certificates should be imported into each other’s client’s trust-stores.
Example of importing node2’s certificates into node1’s trust-stores. Vice-versa needs to be done as well for node2:
<Path_to_JAVA_JDK_Installation>/bin/keytool -import -trustcacerts -alias wipNode2_Certificates/wipNode2-server-chain.pem -file wipNode2_Certificates/wipNode2-ca-cert.pem -keystore wipNode1-server-truststore.jks -storepass password
<Path_to_JAVA_JDK_Installation>/bin/keytool -import -trustcacerts -alias wipNode2_Certificates/ wipNode2-client-chain.pem -file wipNode2_Certificates/ wipNode2-ca-cert.pem -keystore wipNode2-client-truststore.jks -storepass password
4. Use the ‘openssl verify‘ command to check that generated certificates are proper.
5. Configure the security rules to allow traffic for communication for configured ports. Further, ensure that there is no security blocker for using self-signed certificates.
D. Various Modes of TLS for Tessera
- CA Mode Configuration file for Tessera:
Below is sample Tessera config file using CA (self-signed CA and Server/Client certificates):
{
“useWhiteList”: false,
“jdbc”: {
“username”: “sa”,
“password”: “”,
“url”: “jdbc:h2:./target/h2/tessera1”,
“autoCreateTables”: true
},
“serverConfigs”:[
{
“app”: “Q2T”,
“enabled”: true,
“serverAddress”: “unix:/home/ubuntu/quorum
documentation/wipNode1/tessera1/tm.ipc”,
“communicationType”: “REST”
},
{
“app”: “P2P”,
“enabled”: true,
“serverAddress”: “https://172.31.26.111:9001",
“communicationType”: “REST”,
“sslConfig”: {
“tls” : “STRICT”,
“generateKeyStoreIfNotExisted” : “false”,
“serverKeyStore” : “/home/ubuntu/quorum
documentation/wipNode1/certificates/wipnode1-server-keystore.jks”,
“serverKeyStorePassword” : “password”,
“serverTrustStore” : “/home/ubuntu/quorum-documentation/ wipNode1/certificates/wipnode1-server-truststore.jks”,
“serverTrustStorePassword” : “password”,
“serverTrustMode” : “CA”,
“clientKeyStore” : “/home/ubuntu/quorum-documentation/ wipNode1/certificates/wipnode1-client-keystore.jks”,
“clientKeyStorePassword” : “password”,
“clientTrustStore” : “/home/ubuntu/quorum-documentation/ wipNode1/certificates/wipnode1-client-keystore.jks”,
“clientTrustStorePassword” : “password”,
“clientTrustMode” : “CA”,
“clientAuth”: “true”
}
}
],
“peer”: [
{
“url”: “https://172.31.26.111:9001"
},
{
“url”: “https://172.31.6.147:9001"
}
],
“keys”: {
“keyData”: [
{
“privateKeyPath”: “/home/ubuntu/quorum-documentation/wipNode1/data/keystore/node1.key”,
“publicKeyPath”: “/home/ubuntu/quorum-documentation/wipNode1/data/keystore/node1.pub”
}
]
},
“alwaysSendTo”: []
}
2. TOFU Mode:
Configuration for SSL using TOFU Mode is as follows:
{
“useWhiteList”: false,
“jdbc”: {
“username”: “sa”,
“password”: “”,
“url”: “jdbc:h2:./target/h2/tessera1”,
“autoCreateTables”: true
},
“serverConfigs”:[
{
“app”:”ThirdParty”,
“enabled”: true,
“serverAddress”: “http://172.31.26.111:9081",
“communicationType”: “REST”
},
{
“app”: “Q2T”,
“enabled”: true,
“serverAddress”: “unix:/home/ubuntu/quorum
documentation/wipNode1/tessera1/tm.ipc”,
“communicationType”: “REST”
},
{
“app”: “P2P”,
“enabled”: true,
“serverAddress”: “https://172.31.26.111:9001",
“communicationType”: “REST”,
“sslConfig”: {
“tls” : “STRICT”,
“generateKeyStoreIfNotExisted” : “true”,
“serverKeyStore” : “/home/ubuntu/quorum-documentation/wipNode1/certificates/wipnode1-server-keystore.jks”,
“serverKeyStorePassword” : “password”,
“serverTrustMode” : “TOFU”,
“clientKeyStore” : “/home/ubuntu/quorum-documentation/ wipNode1/certificates/wipnode1-client-keystore.jks “,
“clientKeyStorePassword” : “password”,
“clientTrustMode” : “TOFU”,
“knownClientsFile” : “knownClients”,
“knownServersFile” : “knownServers”
}
}
],
“peer”: [
{
“url”: “https://172.31.26.111:9001"
},
{
“url”: “https://172.31.6.147:9001"
}
],
“keys”: {
“passwordFile”: “/home/ubuntu/quorum- documentation/wipNode1/Node-1/passwd”,
“keyData”: [
{
“privateKeyPath”: “/home/ubuntu/quorum-documentation/wipNode1/data/keystore/node1.key”,
“publicKeyPath”: “/home/ubuntu/quorum-documentation/wipNode1/data/keystore/node1.pub”
}
]
},
“alwaysSendTo”: []
}
3. WHITELIST Mode:
SSL configuration for WHITELIST mode is as follows:
{
“useWhiteList”: false,
“jdbc”: {
“username”: “sa”,
“password”: “”,
“url”: “jdbc:h2:./target/h2/tessera1”,
“autoCreateTables”: true
},
“serverConfigs”:[
{
“app”:”ThirdParty”,
“enabled”: true,
“serverAddress”: “http://172.31.26.111:9081",
“communicationType”: “REST”
},
{
“app”: “Q2T”,
“enabled”: true,
“serverAddress”: “unix:/home/ubuntu/quorum-documentation/wipNode1/tessera1/tm.ipc”,
“communicationType”: “REST”
},
{
“app”: “P2P”,
“enabled”: true,
“serverAddress”: “https://172.31.26.111:9001",
“communicationType”: “REST”,
“sslConfig”: {
“tls” : “STRICT”,
“generateKeyStoreIfNotExisted” : “true”,
“serverKeyStore” : “/home/ubuntu/quorum-documentation/wipNode1/certificates/wipnode1-server-keystore.jks”,
“serverKeyStorePassword” : “password”,
“serverTrustMode” : “WHITELIST”,
“clientKeyStore” : “/home/ubuntu/quorum-documentation/wipNode1/certificates/wipnode1-client-keystore.jks “,
“clientKeyStorePassword” : “password”,
“clientTrustMode” : “WHITELIST”,
“knownClientsFile” : “knownClients”,
“knownServersFile” : “knownServers”
}
}
],
“peer”: [
{
“url”: “https://172.31.26.111:9001"
},
{
“url”: “https://172.31.6.147:9001"
}
],
“keys”: {
“passwordFile”: “/home/ubuntu/quorum- documentation/wipNode1/passwd”,
“keyData”: [
{
“privateKeyPath”: “/home/ubuntu/quorum-documentation/wipNode1/data/keystore/node1.key”,
“publicKeyPath”: “/home/ubuntu/quorum-documentation/wipNode1/data/keystore/node1.pub”
}
]
},
“alwaysSendTo”: []
}
By: Maneesh Grover, Rakesh Kumar Chinubhai Lunagariya, and Tejas Pradeep Borawake