Fully functional mTLS implementation with Java Spring Boot. The solution is represented by these two entities: Enterprise (client) and the Bank (server).
👉 Before running the application all setup steps must be executed
Add the DNS configuration to the /etc/hosts/
files.
ℹ️ If using WSL, edit the Windows hosts file as well as it replaces the WSL file on reboot
localhost api.bank.local
::1 api.bank.local
Initiate the server:
./mvnw spring-boot:run
Initiate the client application:
mvn package
mvn exec:exec
To check for dependencies and plugins updates:
mvn versions:display-dependency-updates
mvn versions:display-plugin-updates
The following sections will demonstrate how to set up the infrastructure prior to running the applications.
Change to the Bank PKI directory:
cd pki/bank
Initialize the directory structure:
bash init.sh
Create the Root CA:
Use password
1234
openssl req -new \
-config root.conf \
-out csr/bank-root.csr \
-keyout private/bank-root.key
Self-sign the Root CA certificate:
Use the previous password, and accept the prompts
openssl ca -selfsign \
-config root.conf \
-in csr/bank-root.csr \
-out certs/bank-root.crt
Create and sign the server certificate:
# Private key
openssl genrsa -out ./private/bank-server.key 4096
# CSR
openssl req -config ./server.conf -key ./private/bank-server.key -subj '/CN=api.bank.local' -new -sha256 -out ./csr/bank-server.csr
# Sign
openssl ca -batch -config ./root.conf -passin pass:1234 -extfile server.conf -extensions v3_req -days 30 -notext -md sha256 -in ./csr/bank-server.csr -out ./certs/bank-server.crt
Create the bundle to will be used by the Spring Boot server application:
The key alias within the keystore will be
1
. Thenoiter
andnomaciter
options must be specified to allow the generated KeyStore to be recognized properly by JSSE. Use password1234
openssl pkcs12 -inkey ./private/bank-server.key -in ./certs/bank-root.crt -in ./certs/bank-server.crt -export -out ./bundles/keystore.p12 \
-noiter -nomaciter
Copy the #PKCS12 bundle to server application directory:
cp bundles/keystore.p12 ../../server/
Copy the Root CA to the client directory:
cp certs/bank-root.crt ../../client/
Change to the Enterprise PKI directory:
cd pki/enterprise
Initialize the directory structure:
bash init.sh
Create the Root CA:
Use password
1234
openssl req -new \
-config root.conf \
-out csr/enterprise-root.csr \
-keyout private/enterprise-root.key
Self-sign the Root CA certificate:
Use the previous password, and accept the prompts
openssl ca -selfsign \
-config root.conf \
-in csr/enterprise-root.csr \
-out certs/enterprise-root.crt
Create and sign the client certificate:
# Private key
openssl genrsa -out ./private/enterprise-client.key 4096
# CSR
openssl req -config ./client.conf -key ./private/enterprise-client.key -subj '/CN=client.enterprise.local' -new -sha256 -out ./csr/enterprise-client.csr
# Sign
openssl ca -batch -config ./root.conf -passin pass:1234 -extfile client.conf -extensions v3_req -days 30 -notext -md sha256 -in ./csr/enterprise-client.csr -out ./certs/enterprise-client.crt
Copy the certificates and client key to the client directory:
cp certs/enterprise-root.crt ../../client/
cp certs/enterprise-client.crt ../../client/
cp private/enterprise-client.key ../../client/
TODO: Implement client truststore
keytool -importcert -trustcacerts -file bank-root.crt -storepass secret -keystore keystore.jks -alias "root.bank.local"
Create and copy the truststore to the server directory:
keytool -import -trustcacerts -file certs/enterprise-root.crt -alias EnterpriseRootCA -keystore bundles/truststore.jks -storepass 123456
cp bundles/truststore.jks ../../server/
Quick client test:
# From the client directory
curl --cert enterprise-client.crt --key enterprise-client.key --cacert bank-root.crt https://api.bank.local:8443
Verifying the contents of requests and certificates:
openssl req -text -noout -verify -in ./csr/bank-server.csr | grep 'DNS'
openssl req -text -noout -verify -in ./csr/bank-server.csr
openssl x509 -text -noout -in ./certs/bank-server.crt
Verify TLS trust with the root CA:
# ❌ This should fail
openssl s_client -showcerts -connect api.bank.local:8443
# ✅ This should work
openssl s_client -showcerts -CAfile certs/bank-root.crt -connect api.bank.local:8443
Verify with client testing:
openssl s_client -cert ./enterprise-client.crt -key ./enterprise-client.key -CAfile bank-root.crt -connect api.bank.local:8443
curl --cert enterprise-client.crt --key enterprise-client.key --cacert bank-root.crt https://api.bank.local:8443
Quick SSL tests can be performed at https://badssl.com/.
Create an environment variable:
- Name:
SSLKEYLOGFILE
- Value:
C:\Users\<USER>\SSLKeys\sslkeylog.log
Start a Wireshark session. In Chrome, navigate the desired site.
In Wireshark > Preferences > Protocols > TLS, add set the (Pre)-Master-Secret log filename.
Filter the traffic:
frame contains "api.bank.local"
https://www.ibm.com/docs/en/hpvs/1.2.x?topic=reference-openssl-configuration-examples
https://stackoverflow.com/questions/5871279/ssl-and-cert-keystore
https://www.feistyduck.com/library/openssl-cookbook/online/openssl-command-line/private-ca-creating-root.html
https://www.feistyduck.com/library/openssl-cookbook/online/openssl-command-line/private-ca-creating-root.html
https://github.com/epomatti/az-iot-dps
https://www.ibm.com/support/pages/how-create-csr-multiple-subject-alternative-name-san-entries-pase-openssl-3rd-party-or-internet-ca
https://www.ibm.com/support/pages/how-create-csr-multiple-subject-alternative-name-san-entries-pase-openssl-3rd-party-or-internet-ca
https://stackoverflow.com/questions/11548336/openssl-verify-return-code-20-unable-to-get-local-issuer-certificate
https://stackoverflow.com/questions/45522363/difference-between-java-keytool-commands-when-importing-certificates-or-chain
https://stackoverflow.com/questions/45522363/difference-between-java-keytool-commands-when-importing-certificates-or-chain
https://www.baeldung.com/x-509-authentication-in-spring-security
https://www.baeldung.com/x-509-authentication-in-spring-security
https://medium.com/geekculture/authentication-using-certificates-7e2cfaacd18b
https://medium.com/@salarai.de/how-to-enable-mutual-tls-in-a-sprint-boot-application-77144047940f