{"id":20697428,"url":"https://github.com/epomatti/mutual-tls","last_synced_at":"2026-04-05T22:06:10.416Z","repository":{"id":224141163,"uuid":"761825183","full_name":"epomatti/mutual-tls","owner":"epomatti","description":"mTLS implementation","archived":false,"fork":false,"pushed_at":"2024-02-27T01:59:21.000Z","size":151,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-13T11:42:45.313Z","etag":null,"topics":["java","maven","mtls","mutual-tls","spring","spring-boot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/epomatti.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-22T15:02:55.000Z","updated_at":"2024-12-06T10:04:31.000Z","dependencies_parsed_at":"2024-02-27T02:47:59.624Z","dependency_job_id":null,"html_url":"https://github.com/epomatti/mutual-tls","commit_stats":null,"previous_names":["epomatti/mutual-tls"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/epomatti/mutual-tls","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epomatti%2Fmutual-tls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epomatti%2Fmutual-tls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epomatti%2Fmutual-tls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epomatti%2Fmutual-tls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/epomatti","download_url":"https://codeload.github.com/epomatti/mutual-tls/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epomatti%2Fmutual-tls/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31451465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T21:22:52.476Z","status":"ssl_error","status_checked_at":"2026-04-05T21:22:51.943Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","maven","mtls","mutual-tls","spring","spring-boot"],"created_at":"2024-11-17T00:18:02.260Z","updated_at":"2026-04-05T22:06:10.376Z","avatar_url":"https://github.com/epomatti.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mutual TLS\n\nFully functional mTLS implementation with Java Spring Boot. The solution is represented by these two entities: Enterprise (client) and the Bank (server).\n\n\u003cimg src=\".assets/mtls.png\" /\u003e\n\n## Execute\n\n👉 Before running the application all setup steps must be executed\n\nAdd the DNS configuration to the `/etc/hosts/` files.\n\n\u003e ℹ️ If using WSL, edit the Windows hosts file as well as it replaces the WSL file on reboot\n\n```\nlocalhost    api.bank.local\n::1          api.bank.local\n```\n\nInitiate the server:\n\n```sh\n./mvnw spring-boot:run\n```\n\nInitiate the client application:\n\n```sh\nmvn package\nmvn exec:exec\n```\n\n### Updates\n\nTo check for dependencies and plugins updates:\n\n```sh\nmvn versions:display-dependency-updates\nmvn versions:display-plugin-updates\n```\n\nThe following sections will demonstrate how to set up the infrastructure prior to running the applications.\n\n## 1 - Create the Server PKI\n\nChange to the Bank PKI directory:\n\n```sh\ncd pki/bank\n```\n\nInitialize the directory structure:\n\n```sh\nbash init.sh\n```\n\nCreate the Root CA:\n\n\u003e Use password `1234`\n\n```sh\nopenssl req -new \\\n    -config root.conf \\\n    -out csr/bank-root.csr \\\n    -keyout private/bank-root.key\n```\n\nSelf-sign the Root CA certificate:\n\n\u003e Use the previous password, and accept the prompts\n\n```sh\nopenssl ca -selfsign \\\n    -config root.conf \\\n    -in csr/bank-root.csr \\\n    -out certs/bank-root.crt\n```\n\nCreate and sign the server certificate:\n\n```sh\n# Private key\nopenssl genrsa -out ./private/bank-server.key 4096\n\n# CSR\nopenssl req -config ./server.conf -key ./private/bank-server.key -subj '/CN=api.bank.local' -new -sha256 -out ./csr/bank-server.csr\n\n# Sign\nopenssl 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\n```\n\nCreate the bundle to will be used by the Spring Boot server application:\n\n\u003e The key alias within the keystore will be `1`.\n\u003e The `noiter` and `nomaciter` options must be specified to allow the generated KeyStore to be recognized properly by JSSE.\n\u003e Use password `1234`\n\n```sh\nopenssl pkcs12 -inkey ./private/bank-server.key -in ./certs/bank-root.crt -in ./certs/bank-server.crt -export -out ./bundles/keystore.p12 \\\n       -noiter -nomaciter\n```\n\nCopy the #PKCS12 bundle to server application directory:\n\n```sh\ncp bundles/keystore.p12 ../../server/\n```\n\nCopy the Root CA to the client directory:\n\n```sh\ncp certs/bank-root.crt ../../client/\n```\n\n## 2 - Create the Client PKI\n\nChange to the Enterprise PKI directory:\n\n```sh\ncd pki/enterprise\n```\n\nInitialize the directory structure:\n\n```sh\nbash init.sh\n```\n\nCreate the Root CA:\n\n\u003e Use password `1234`\n\n```sh\nopenssl req -new \\\n    -config root.conf \\\n    -out csr/enterprise-root.csr \\\n    -keyout private/enterprise-root.key\n```\n\nSelf-sign the Root CA certificate:\n\n\u003e Use the previous password, and accept the prompts\n\n```sh\nopenssl ca -selfsign \\\n    -config root.conf \\\n    -in csr/enterprise-root.csr \\\n    -out certs/enterprise-root.crt\n```\n\nCreate and sign the client certificate:\n\n```sh\n# Private key\nopenssl genrsa -out ./private/enterprise-client.key 4096\n\n# CSR\nopenssl req -config ./client.conf -key ./private/enterprise-client.key -subj '/CN=client.enterprise.local' -new -sha256 -out ./csr/enterprise-client.csr\n\n# Sign\nopenssl 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\n```\n\nCopy the certificates and client key to the client directory:\n\n```sh\ncp certs/enterprise-root.crt ../../client/\ncp certs/enterprise-client.crt ../../client/\ncp private/enterprise-client.key ../../client/\n```\n\n\u003e TODO: Implement client truststore\n\n```sh\nkeytool -importcert -trustcacerts -file bank-root.crt -storepass secret -keystore keystore.jks -alias \"root.bank.local\"\n```\n\nCreate and copy the truststore to the server directory:\n\n```sh\nkeytool -import -trustcacerts -file certs/enterprise-root.crt -alias EnterpriseRootCA -keystore bundles/truststore.jks -storepass 123456\n\ncp  bundles/truststore.jks ../../server/\n```\n\nQuick client test:\n\n```sh\n# From the client directory\ncurl --cert enterprise-client.crt --key enterprise-client.key --cacert bank-root.crt https://api.bank.local:8443\n```\n\n## Troubleshooting\n\nVerifying the contents of requests and certificates:\n\n```sh\nopenssl req -text -noout -verify -in ./csr/bank-server.csr | grep 'DNS'\nopenssl req -text -noout -verify -in ./csr/bank-server.csr\nopenssl x509 -text -noout -in ./certs/bank-server.crt\n```\n\nVerify TLS trust with the root CA:\n\n```sh\n# ❌ This should fail\nopenssl s_client -showcerts -connect api.bank.local:8443\n\n# ✅ This should work\nopenssl s_client -showcerts -CAfile certs/bank-root.crt -connect api.bank.local:8443\n```\n\nVerify with client testing:\n\n```sh\nopenssl s_client -cert ./enterprise-client.crt -key ./enterprise-client.key -CAfile bank-root.crt -connect api.bank.local:8443\n\ncurl --cert enterprise-client.crt --key enterprise-client.key --cacert bank-root.crt https://api.bank.local:8443\n```\n\nQuick SSL tests can be performed at https://badssl.com/.\n\n### Wireshark TLS\n\nCreate an environment variable:\n\n- Name: `SSLKEYLOGFILE`\n- Value: `C:\\Users\\\u003cUSER\u003e\\SSLKeys\\sslkeylog.log`\n\nStart a Wireshark session. In Chrome, navigate the desired site.\n\nIn Wireshark \u003e Preferences \u003e Protocols \u003e TLS, add set the (Pre)-Master-Secret log filename.\n\nFilter the traffic:\n\n```\nframe contains \"api.bank.local\"\n```\n\n## References\n\n[1]: https://docs.oracle.com/cd/E19509-01/820-3503/ggfhb/index.html\n[2]: https://www.phcomp.co.uk/Tutorials/Web-Technologies/Understanding-and-generating-OpenSSL.cnf-files.html\n[3]: https://www.mojohaus.org/exec-maven-plugin/usage.html\n\n```\nhttps://www.ibm.com/docs/en/hpvs/1.2.x?topic=reference-openssl-configuration-examples\nhttps://stackoverflow.com/questions/5871279/ssl-and-cert-keystore\nhttps://www.feistyduck.com/library/openssl-cookbook/online/openssl-command-line/private-ca-creating-root.html\nhttps://www.feistyduck.com/library/openssl-cookbook/online/openssl-command-line/private-ca-creating-root.html\nhttps://github.com/epomatti/az-iot-dps\nhttps://www.ibm.com/support/pages/how-create-csr-multiple-subject-alternative-name-san-entries-pase-openssl-3rd-party-or-internet-ca\nhttps://www.ibm.com/support/pages/how-create-csr-multiple-subject-alternative-name-san-entries-pase-openssl-3rd-party-or-internet-ca\nhttps://stackoverflow.com/questions/11548336/openssl-verify-return-code-20-unable-to-get-local-issuer-certificate\nhttps://stackoverflow.com/questions/45522363/difference-between-java-keytool-commands-when-importing-certificates-or-chain\nhttps://stackoverflow.com/questions/45522363/difference-between-java-keytool-commands-when-importing-certificates-or-chain\nhttps://www.baeldung.com/x-509-authentication-in-spring-security\nhttps://www.baeldung.com/x-509-authentication-in-spring-security\nhttps://medium.com/geekculture/authentication-using-certificates-7e2cfaacd18b\nhttps://medium.com/@salarai.de/how-to-enable-mutual-tls-in-a-sprint-boot-application-77144047940f\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepomatti%2Fmutual-tls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fepomatti%2Fmutual-tls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepomatti%2Fmutual-tls/lists"}