Skip to content
Ashish.
All posts
Diagram showing the bidirectional trust model of mTLS versus standard TLS.
6 min readDevelopmentBeginnerFeatured#tls#mtls#security#handshake#keystore#truststore#networking

TLS and mTLS Fundamentals

An examination of TLS and mTLS protocols, covering handshake mechanics, keystores, and truststores for secure backend communication.

By Ashish KumarPart 1 of mTLS With Spring Boot

In backend systems, securing communication is not merely about encrypting data; it is about establishing a chain of trust. Most engineers understand TLS as the mechanism that prevents eavesdropping. However, when building service meshes or microservices architectures, standard TLS is insufficient because it only verifies the server's identity. Mutual TLS (mTLS) introduces bidirectional authentication, ensuring that both the client and the server verify each other's cryptographic identities before any application data is exchanged. This process relies on the complexity of the handshake, the management of keystores, and the validation of truststores.

This article is Part 1 of the mTLS With Spring Boot series. To understand mTLS, we must first dissect the mechanics of the standard TLS handshake, then examine how the protocol extends to require client proof, and finally map these concepts to the concrete artifacts used in Java-based backends: keystores and truststores.

The TLS Handshake Mechanism

Standard TLS operates on an asymmetric-to-symmetric encryption model. The goal is to establish a shared secret without transmitting it over the network, then use that secret for fast symmetric encryption (AES-GCM or ChaCha20).

Consider a client (ClientA) connecting to a server (ServerB). The process begins with a ClientHello message, where ClientA lists supported cipher suites and TLS versions. ServerB responds with a ServerHello, selecting the strongest mutually supported cipher suite, and immediately sends its Certificate. This certificate contains ServerB's public key and is signed by a Certificate Authority (CA).

ClientA must verify this certificate. It checks the signature against a known root CA stored in its local trust anchor. If valid, ClientA generates a Pre-Master Secret, encrypts it with ServerB's public key, and sends it in a ClientKeyExchange message. Only ServerB can decrypt this using its private key.

Both parties then derive the Master Secret from the Pre-Master Secret and random values exchanged earlier. From this, they generate identical session keys. All subsequent traffic is encrypted with these symmetric keys. The mechanism ensures confidentiality and server authenticity, but it does not require ClientA to prove its identity. ServerB trusts any client that can successfully complete the handshake, assuming the network path is secure.

Introducing mTLS and the Client Certificate Request

Mutual TLS modifies the handshake to include a critical step: the server demands proof of identity from the client. After ServerB sends its Certificate and CertificateRequest messages, it explicitly asks the client to provide its own certificate.

The CertificateRequest message contains the distinguished names of CAs that the server trusts. This is a filter: if ClientA has a certificate issued by a CA not listed here, it should not send it. ClientA then responds with its Certificate message, containing its public key and identity chain.

Now, the roles reverse. ServerB must verify ClientA's certificate against its own trust store. If the validation fails—due to expiration, revocation, or an untrusted CA—ServerB sends an alert such as certificate_expired, certificate_revoked, or unknown_ca and terminates the connection.

If validation succeeds, ClientA sends a CertificateVerify message. This is a digital signature over all previous handshake messages, created using ClientA's private key. This proves that ClientA possesses the private key corresponding to the public key in its certificate. Without this step, an attacker could present a stolen certificate but would lack the private key needed to sign the handshake.

Keystores vs. Truststores: The Artifact Distinction

In Java-based backends, confusion often arises between KeyStore and TrustStore. While both are typically PKCS12 or JKS files, they serve opposite roles in the trust model. A truststore is the repository for trusted certificates, while a keystore holds private identities.

A KeyStore holds your private identity. It contains private keys and the associated certificates that prove who you are. In an mTLS context, this is your client certificate. You use this to sign the CertificateVerify message and decrypt messages sent to you.

A TrustStore holds the certificates of entities you trust. It contains root CA certificates and intermediate CAs. When you receive a certificate from another party, you look up the issuer in your TrustStore to validate the signature chain. You never put private keys in a TrustStore.

In mTLS, both services act as both holders and verifiers of certificates, not issuers. Issuance is the role of the Certificate Authority. Service A needs a KeyStore to present its identity to Service B, and a TrustStore to verify Service B's identity. Service B requires the same. This symmetry is effective for internal service-to-service communication, as it eliminates the need for external identity providers or shared secrets like API keys.

Backend Implementation Scenario

Consider a microservices architecture where OrderService (ClientA) calls PaymentService (ServerB). Both services run on Java.

  1. Configuration: OrderService is configured with client.jks (its KeyStore) and truststore.jks (its TrustStore). PaymentService is configured with server.jks (its KeyStore) and truststore.jks (its TrustStore).
  2. Handshake: When OrderService initiates the connection, it sends its Certificate and CertificateVerify signature, establishing the mTLS channel.
  3. Validation: PaymentService checks OrderService's certificate against its truststore.jks. If OrderService's CA is not in PaymentService's truststore, the connection is rejected.
  4. Mutual Trust: OrderService simultaneously validates PaymentService's certificate against its own truststore.jks.

This bidirectional verification ensures that OrderService is talking to the legitimate PaymentService, and PaymentService knows exactly which service is making the request. No shared passwords or API keys are transmitted. The security relies entirely on the cryptographic integrity of the certificates and the private keys protected in the keystores.

Understanding this mechanism is foundational for implementing mTLS in frameworks like Spring Boot, where the underlying SSLContext manages these keystores and truststores automatically.

Conclusion

mTLS shifts the security model from a single point of trust to a mutual verification of cryptographic identities. By requiring both the client and server to present and validate certificates, mTLS ensures that only authorized services can communicate within a backend system. This foundation of keystores and truststores is essential for securing microservices architectures before moving to higher-level implementations in frameworks like Spring Boot.

Related posts