Skip to content

Instantly share code, notes, and snippets.

@usmansaleem
Last active January 19, 2023 01:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save usmansaleem/1989d7aecb3260bc816e62ca36a60efe to your computer and use it in GitHub Desktop.
Save usmansaleem/1989d7aecb3260bc816e62ca36a60efe to your computer and use it in GitHub Desktop.
Custom Root CA and signed server (Web3Signer) TLS certificates using openssl

Generate Root CA, Web3Signer server and client certificate

This example uses openssl utility to generate custom CA and signs web3signer and client certs and shows how to setup Web3Signer with them. The keytool example can be seen here.

Generate Root CA key pair (CN=root.mycompany.com)

openssl genrsa -out root_ca.key 4096

Create root CSR and self-sign (Modify CN as per your requirements).

openssl req -x509 -nodes -sha256 -new -key root_ca.key -out root_ca.crt -days 1024 \
  -subj "/CN=root.mycompany.com" \
  -addext "keyUsage = critical, keyCertSign" \
  -addext "basicConstraints = critical, CA:TRUE, pathlen:0" \
  -addext "subjectKeyIdentifier = hash"

Generate Web3Signer certificate and CSR

The Web3Signer certificate CN should be the hostname where web3signer is hosted. In this example, I am using localhost. The san extension should be used to specify the all the hostnames and IP addresses from which Web3Signer is served. Modify following commands according to your requirements.

Generate key pair

openssl genrsa -out web3signer.key 2048

Create openssl configuration for web3signer

cat <<EOF >./server_openssl.conf
$(cat /etc/ssl/openssl.cnf)
[SAN]
subjectAltName=DNS:localhost,DNS:www.localhost,IP:127.0.0.1
EOF

Create CSR (Modify -subj as per your requirements.)

openssl req -new -sha256 \
    -key web3signer.key \
    -subj "/C=AU/ST=QLD/O=Consensys/OU=Protocols/CN=localhost" \
    -reqexts SAN \
    -config ./server_openssl.conf \
    -out web3signer.csr

Verify the CSR

openssl req  -in web3signer.csr -noout -text

Sign CSR using Root CA

Create openssl configuration for signing web3signer. Modify Subject Alt Names accordingly.

cat << EOF >./web3signer_san_openssl.conf
[req]
default_bits       = 2048
distinguished_name = req_distinguished_name
req_extensions     = req_ext

[req_distinguished_name]
countryName                 = AU
stateOrProvinceName         = QLD
organizationName           = Consensys
commonName                 = localhost

[req_ext]
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
basicConstraints = CA:FALSE
authorityKeyIdentifier = keyid:always
subjectAltName = @alt_names

[alt_names]
DNS.1   = localhost
DNS.2   = www.localhost
IP.1    = 127.0.0.1
IP.2    = 10.0.0.1
EOF
openssl x509 -req -in web3signer.csr -CA ./root_ca.crt -CAkey ./root_ca.key \
		-CAcreateserial -out web3signer.crt -days 500 -sha256 \
		-extfile web3signer_san_openssl.conf -extensions req_ext

Verify crt

openssl x509 -in web3signer.crt -text -noout

Convert web3signer certificates to PKCS12

Now that we have signed certificates, we need to convert it to PKCS12 so that it can be used by Web3Signer. Using password 123456.

openssl pkcs12 -export \
-certfile root_ca.crt \
-inkey web3signer.key \
-in web3signer.crt \
-out web3signer_keystore.p12

Verify pkcs12 keystore

openssl pkcs12 -info -in web3signer_keystore.p12

Set up Web3Signer with TLS (without mutual authentication)

web3signer_keystore.p12 now contains full CA chain as well as signed certificate. Time to get Web3Signer start with TLS enabled. In the following example, Web3Signer is using tls-allow-any-client: true.

Create docker-compose.yml and web3signer configuration

mkdir -p ./config/keys
cp ./web3signer_keystore.p12 ./config
cat <<EOF >./config/password.txt
123456
EOF
cat <<EOF >./config/config.yaml
http-listen-host: "0.0.0.0"
http-listen-port: 9000
http-host-allowlist: "*"

key-store-path: /var/config/keys

# tls options
tls-keystore-file: /var/config/web3signer_keystore.p12 
tls-keystore-password-file: /var/config/password.txt 
# tls-known-clients-file: /var/config/knownClients.txt
tls-allow-any-client: true

# eth2 subcommand options
eth2.slashing-protection-enabled: false
EOF
cat <<EOF >./docker-compose.yaml
version: "3.9"
   
services:
  web3signer:
    image: consensys/web3signer:develop
    command: --config-file=/var/config/config.yaml eth2
    volumes:
      - ./config:/var/config
    ports:
      - "9000:9000"
EOF

Run Web3Signer using docker compose

docker compose up

...
tlscerts-web3signer-1  | 2023-01-17 02:52:59.659+00:00 | pool-2-thread-1 | INFO  | DefaultArtifactSignerProvider | Total signers (keys) currently loaded in memory: 0
tlscerts-web3signer-1  | 2023-01-17 02:53:00.140+00:00 | main | INFO  | Runner | Web3Signer has started with TLS enabled, and ready to handle signing requests on 0.0.0.0:9000

Use curl with upcheck

» curl --cacert ./root_ca.crt https://localhost:9000/upcheck
OK%

Web3Signer TLS with Mutual Authentication

Following scenario means that client will present its certificate to web3Signer for mutual TLS authentication. Hence Web3Signer needs to add the client's certificate fingerprint in the known clients.

Generate client certificate and CSR

This example will be using curl utility to connect to web3signer. Hence the file names are named curl.crt and curl.key accordingly.

openssl genrsa -out curl.key 2048

Create openssl configuration for client

cat <<EOF >./curl_openssl.conf
$(cat /etc/ssl/openssl.cnf)
[SAN]
subjectAltName=DNS:localhost,IP:127.0.0.1
EOF

Create the CSR. Note that the value of client CN will be used by Web3Signer in its knownClients.txt file later on.

openssl req -new -sha256 \
    -key curl.key \
    -subj "/CN=curl" \
    -reqexts SAN \
    -config ./curl_openssl.conf \
    -out curl.csr

Verify CSR

openssl req  -in curl.csr -noout -text

Sign Client CSR using Root CA

Create openssl configuration for client (curl) certificate. Make sure to note commonName as it will be used by Web3Signer later on in knownClients.txt file.

cat << EOF >./curl_san_openssl.conf
[req]
default_bits       = 2048
distinguished_name = req_distinguished_name
req_extensions     = req_ext

[req_distinguished_name]
countryName                 = AU
stateOrProvinceName         = QLD
organizationName           = Consensys
commonName                 = curl

[req_ext]
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
basicConstraints = CA:FALSE
authorityKeyIdentifier = keyid:always
subjectAltName = @alt_names

[alt_names]
DNS.1   = localhost
DNS.2   = www.localhost
IP.1    = 127.0.0.1
EOF
openssl x509 -req -in curl.csr -CA ./root_ca.crt -CAkey ./root_ca.key \
		-CAcreateserial -out curl.crt -days 500 -sha256 \
		-extfile curl_san_openssl.conf -extensions req_ext

Verify crt

openssl x509 -in curl.crt -text -noout

Client certificate fingerprint. This will be used later on by Web3Signer knownClients.txt file. The actual value might be different in your example.

openssl x509 -in curl.crt  -noout -fingerprint
SHA256 Fingerprint=77:3E:E6:5F:47:92:33:FA:94:EF:15:79:3C:1C:14:D1:91:D8:8F:4C:C7:83:D7:CA:29:88:E5:81:44:5F:23:38

Create knownClients.txt file in ./config using the CN curl as alias and certificate fingerprint.

cat <<EOF >./config/knownClients.txt
curl 77:3E:E6:5F:47:92:33:FA:94:EF:15:79:3C:1C:14:D1:91:D8:8F:4C:C7:83:D7:CA:29:88:E5:81:44:5F:23:38
EOF

Modify Web3Signer's config file ./config/config.yaml

Modify Web3Signer's config file so that it uses the knownClients.txt file and commented out tls-allow-any-client (or set it to false). The tls options should look like:

...
# tls options
tls-keystore-file: /var/config/web3signer_keystore.p12
tls-keystore-password-file: /var/config/password.txt
tls-known-clients-file: /var/config/knownClients.txt
# tls-allow-any-client: true
...

Bring Web3Signer up (via docker compose)

docker compose up

Connect to Web3Signer using curl (TLS mutual authentication)

curl --cacert ./root_ca.crt \
--cert ./curl.crt \
--key ./curl.key \
https://localhost:9000/upcheck
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment