Certificate formats and converting between them

  • PEM format - base64-encoded format, identified by (BEGIN/END CERTIFICATE). Also sometimes used with extension .crt
  • DER format - a binary format, e.g. as produced by Java keytool -export ...

openssl Cookbook

Read a PEM certificate

openssl x509 -in my_cert.pem -noout -text

Read a PEM file

openssl x509 -in my_cert.der -inform DER -noout -text

Convert a CRT to a PEM, via DER intermediary format

openssl x509 -in <filename>.crt -out <filename>.der -outform DER
openssl x509 -in <filename>.der -inform DER -out <filename>.pem -outform PEM

View the issuer for a certificate

openssl x509 -in mycert.pem -noout -issuer

View the entire certificate chain (when all certs are in a single .PEM file)

openssl crl2pkcs7 -nocrl -certfile bundle.pem | openssl pkcs7 -print_certs -noout

Fetch certificate from a host and print its full details (useful for inspecting extensions such as Subject Alternative Names)

echo | openssl s_client -servername ${REMOTE_HOST} -connect ${REMOTE_HOST}:443 2>/dev/null | openssl x509 -noout -text

Fetch certificate from a host and import into a Java truststore

REMOTE_HOST=myserver.example.com

echo | openssl s_client -servername ${REMOTE_HOST} -connect ${REMOTE_HOST}:443 2>/dev/null | openssl x509 > ${REMOTE_HOST}.pem

keytool -import -alias server -file ${REMOTE_HOST}.pem -keystore trust.jks

Fetch all certificates in a chain and output as individual PEM files

Courtesy of https://unix.stackexchange.com/questions/368123/how-to-extract-the-root-ca-and-subordinate-ca-from-a-certificate-chain-in-linux

REMOTE_HOST=myserver.example.com

openssl s_client -showcerts -verify 5 -connect ${REMOTE_HOST}:443 < /dev/null | awk '/BEGIN/,/END/{ if(/BEGIN/){a++}; out="cert"a".pem"; print >out}'; for cert in *.pem; do newname=$(openssl x509 -noout -subject -in $cert | sed -nE 's/.*CN ?= ?(.*)/\1/; s/[ ,.*]/_/g; s/__/_/g; s/_-_/-/; s/^_//g;p' | tr '[:upper:]' '[:lower:]').pem; echo "${newname}"; mv "${cert}" "${newname}"; done

Get fingerprint for an AWS key pair

Verify an AWS key pair against the fingerprint given in the EC2 Console (useful if you’ve got a .pem file lying around and you’re not sure if it’s the right Private Key for AWS):

openssl pkcs8 -in awskeypair.pem -inform PEM -outform DER -topk8 -nocrypt | openssl sha1 -c

Fetch a tls.crt from a Kubernetes secret and display its information

Use jq and openssl to display information about a certificate in a Kubernetes Secret (e.g. to know whether it’s expired, etc.):

oc get secret my-secret -o json | jq -r '.data."tls.key"' | base64 -d - | openssl x509 -noout -text

Creating your own CA and intermediate certs

This will generate:

  • Your own root certificate authority (CA) cert, NotVeriSign, Inc. and private key (notverisign-ca)

  • An intermediate certificate (acmeplc) for the company, ACME plc, signed by NotVeriSign

  • The server’s certificate (cloudapps), which is issued as a wildcard so that it can be used with multiple domains

How to do it:

# generates a private key for NotVerySigned
openssl genrsa -out notverysigned-ca.key 2048

# Generate a self-signed certificate for our new Certificate Authority, NotVeriSign
openssl req -new -x509 -key notverysigned-ca.key -out notverysigned-root-ca.crt -subj "/C=GB/ST=London/L=London/O=NotVerySigned Uncertificates Ltd/CN=NotVerySigned Root CA"

# (Optional) inspect the root CA cert
openssl x509 -in notverysigned-root-ca.crt -noout -text

# Generate a private key for the intermediate certificate
openssl genrsa -out acmeplc.key 2048

# Generate a certificate signing request (CSR) for ACME plc using the private key
openssl req -new -key acmeplc.key -out acmeplc.csr -subj "/C=GB/ST=London/L=London/O=Acme plc/OU=Security Department/CN=ACME plc Intermediate"

# (Optional) inspect the CSR
openssl req -in acmeplc.csr -noout -text

# (Optional) check the Signature Algorithm
openssl req -in acmeplc.csr -noout -text | grep 'Signature Algorithm'

# Using NotVeriSign's private key, sign the ACME plc certificate.
openssl x509 -req -in acmeplc.csr -CA notverysigned-root-ca.crt -CAkey notverysigned-ca.key -CAcreateserial -out acmeplc.crt

# (Optional) inspect the signed certificate - should show "Issuer" as "NotVeriSign Certificates Inc"
openssl x509 -in acmeplc.crt -noout -text

# Create a private key for the cloudapps cert
openssl genrsa -out acmeplc-cloudapps.key 2048

# Generate a CSR to be signed by the ACME intermediate cert.
openssl req -new -key acmeplc-cloudapps.key -out acmeplc-cloudapps.csr -subj "/C=GB/ST=London/L=London/O=Acme plc/OU=Cloud Apps/CN=*.cloudapps.acmeplc.xyz"

# Using ACME's private key, sign the ACME-cloudapps certificate.
openssl x509 -req -in acmeplc-cloudapps.csr -CA acmeplc.crt -CAkey acmeplc.key -CAcreateserial -out acmeplc-cloudapps.crt

# Create a bundle of all three certs
cat notverysigned-root-ca.crt acmeplc.crt acmeplc-cloudapps.crt > chain-all.pem
cat notverysigned-root-ca.crt acmeplc.crt > chain-cas.pem

Now import these for use with Java:

# Produce a password-protected file containing our public cert and private key.
openssl pkcs12 -export -in chain-all.pem -inkey cloudapps.key -out cloudapps.p12 -name cloudapps -passout pass:secretsquirrel
-CAfile chain-ca.pem

# Use Java's keytool to import the p12 bundle to a new keystore
keytool -importkeystore -alias cloudapps -srcstoretype PKCS12 -srckeystore cloudapps.p12 -srcstorepass secretsquirrel -destkeystore server.jks -deststorepass secretsquirrel -deststoretype pkcs12

# Import the chain of CAs into the trust store so that Java trusts them.
keytool -import -noprompt -trustcacerts -alias chain -file chain-cas.pem -keystore server.jks -storepass secretsquirrel

Certificate management on RHEL

To add a certificate in the simple PEM or DER file formats to the list of CAs trusted on the system, copy it to /etc/pki/ca-trust/source/anchors/, then run:

update-ca-trust extract

NOTE this will only work if the certificate has CA:TRUE set in its X509v3 Basic Constraints field.

SSL testing

Make a test request to a host using Server Name Identification (SNI):

openssl s_client -connect myhost.example.com:443 -servername myhost.example.com

Get the SHA1 fingerprint of a certificate (to be able to compare against keystore, etc.):

openssl s_client -connect <host>:<port> < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin

SSL and TLS with Java

Java keystore/truststore properties

javax.net.ssl.keyStore
javax.net.ssl.keyStorePassword

Java SSL debug logging

Enable Java SSL debug logging:

JAVA_OPTS="$JAVA_OPTS -Djavax.net.debug=ssl,handshake"

And some other options/variations:

-Djava.security.debug=certpath,provider
-Djavax.net.debug=ssl,keymanager,trustmanager

Java keytool cookbook

Create self-signed certificates for a server and client, and add each certificate into the other party’s truststore:

keytool -genkey -alias server -keypass changeit -keyalg RSA -keystore server.ks -dname "CN=server,L=Gimmerton" -storepass changeit
keytool -genkey -alias client -keypass changeit -keyalg RSA -keystore client.ks -dname "CN=client,L=Gimmerton" -storepass changeit

keytool -export -alias server -keystore server.ks -file server_cert -storepass changeit
keytool -import -alias server -keystore client.ts -file server_cert -storepass changeit -noprompt

keytool -export -alias client -keystore client.ks -file client_cert -storepass changeit
keytool -import -alias client -keystore server.ts -file client_cert -storepass changeit -noprompt

Java SSL testing

Use the testing tool from UniconLabs:

git clone https://github.com/UniconLabs/java-keystore-ssl-test
cd java-keystore-ssl-test
mvn clean install
java -jar target/java-keystore-test-0.1.0.jar http://amq-interconnect-amqps-basic-demo.192.168.42.248.nip.io

Java SSL troubleshooting

Client authentication (mutual authentication/2-way SSL) isn’t working:

  • Ensure that the needsClientAuth flag is set to true
  • Ensure that the client’s certificate has been added into the server’s truststore.
  • The server first presents an acceptable list of certificates to the client; the client reads this list and tries to present an acceptable certificate, if it can. If the client presents no certificate (<Empty>), then it’s because the client couldn’t find any certificate to present which matched the client’s accepted list.
  • If “Warning: no suitable certificate found - continuing without client authentication” is seen in the Java handshake SSL debug logs, verify that the server is using the correct truststore.