Skip to main content

mTLS


The client and the server interaction, sequence diagram - 




Configuring Keystores (JKS) and Truststores for mTLS in Java

Configuring Keystores (JKS) and Truststores for mTLS in Java

1. What Are Keystore and Truststore?

Keystore (JKS): Stores private keys and public certificates.
Truststore: Stores trusted CA certificates.

Component Purpose Contains
Keystore (JKS) Stores private keys and public certificates Private key + Public Certificate
Truststore Stores trusted CA certificates CA Certificates + Trusted Public Certificates

2. Generating Keystore and Truststore

Step 1: Generate Server Keystore (JKS)

keytool -genkeypair -alias server -keyalg RSA -keysize 2048 \
    -dname "CN=server, OU=IT, O=Company, L=City, ST=State, C=IN" \
    -keystore server-keystore.jks -storepass changeit -validity 365

Step 2: Export Server Certificate

keytool -exportcert -alias server -keystore server-keystore.jks \
    -file server-cert.cer -storepass changeit

Step 3: Create Server Truststore

keytool -importcert -alias client -file client-cert.cer \
    -keystore server-truststore.jks -storepass changeit

Step 4: Generate Client Keystore (JKS)

keytool -genkeypair -alias client -keyalg RSA -keysize 2048 \
    -dname "CN=client, OU=IT, O=Company, L=City, ST=State, C=IN" \
    -keystore client-keystore.jks -storepass changeit -validity 365

Step 5: Export Client Certificate

keytool -exportcert -alias client -keystore client-keystore.jks \
    -file client-cert.cer -storepass changeit

Step 6: Create Client Truststore

keytool -importcert -alias server -file server-cert.cer \
    -keystore client-truststore.jks -storepass changeit

3. Configure Java Application for mTLS

Server Configuration (Spring Boot)

server.ssl.key-store=classpath:server-keystore.jks
server.ssl.key-store-password=changeit
server.ssl.key-alias=server
server.ssl.trust-store=classpath:server-truststore.jks
server.ssl.trust-store-password=changeit
server.ssl.client-auth=need

Client Configuration (Java HTTP Client)

SSLContext sslContext = SSLContext.getInstance("TLS");

// Load Client Keystore
KeyStore keyStore = KeyStore.getInstance("JKS");
try (FileInputStream fis = new FileInputStream("client-keystore.jks")) {
    keyStore.load(fis, "changeit".toCharArray());
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyStore, "changeit".toCharArray());

// Load Truststore
KeyStore trustStore = KeyStore.getInstance("JKS");
try (FileInputStream fis = new FileInputStream("client-truststore.jks")) {
    trustStore.load(fis, "changeit".toCharArray());
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustStore);

sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

HttpClient client = HttpClient.newBuilder()
    .sslContext(sslContext)
    .build();

4. Summary

Step Server Client
1. Generate Keystore server-keystore.jks client-keystore.jks
2. Export Certificate server-cert.cer client-cert.cer
3. Create Truststore server-truststore.jks client-truststore.jks
4. Configure Application Keystore & Truststore setup Keystore & Truststore setup

5. Key Takeaways

  • Keystore stores private keys and certificates.
  • Truststore stores trusted CA certificates.
  • Certificates must be exchanged once manually but used automatically.
  • Java applications must be configured correctly with Keystore & Truststore.

Comments

Popular posts from this blog

Hexagonal Architecture (Ports & Adapters Pattern)

Hexagonal Architecture , also known as the Ports and Adapters pattern, is a software design pattern that aims to create a decoupled and maintainable application by separating the core business logic from external concerns (like databases, APIs, and UIs). Structure of Hexagonal Architecture A typical Hexagonal Architecture has three main layers: 1️⃣ Core Domain (Application Logic) This contains the business rules and domain models. It is completely independent of external technologies . Example: If you’re building a banking system , this part would include logic for transactions, withdrawals, and deposits . 2️⃣ Ports (Interfaces) These are interfaces that define how the core interacts with external components. Two types of ports: Inbound Ports (driven by external inputs like APIs, UI, or events) Outbound Ports (used to interact with external services like databases, messaging systems, etc.) 3️⃣ Adapters (Implementation of Ports) These are concrete implementations of the ports, re...

"Action-Oriented, Stakeholder-Focused" MoM Structure

  I. Meeting Header: Meeting Title:  Clear and concise (e.g., "Project X Status Update," "Q3 Planning Meeting"). Date and Time:  Record the date and time the meeting took place. Location/Platform:  Indicate where the meeting was held (e.g., Conference Room A, Zoom). Attendees:  List the names and roles of everyone who attended. Absent:  List the names of key individuals who were invited but did not attend. Meeting Owner : Who was in charge of the meeting ? Document owner : Who is in charge of the documentation ? II. Key Discussion Points (Concise Summary): Purpose:  Briefly summarize the main topics discussed. Format:  Use bullet points for brevity. Content: Decision Points:  Clearly state any decisions that were made. Key Information:  Summarize any crucial information shared. Key Questions : Summarize the key questions that were raised. Open Issues:  Note any issues that remain unresolved. Stakeholder Focus:  Frame the summar...

Recursion & Choice

Understanding Recursion and Choice Diagrams with Examples Understanding Recursion and Choice Diagrams with Examples Recursion is a powerful concept in programming where a function calls itself to solve smaller instances of the same problem. It's often used in solving complex problems that can be broken down into simpler subproblems. In this blog post, we'll explore the basics of recursion, understand choice diagrams, and see examples to illustrate these concepts. What is Recursion? Recursion occurs when a function calls itself directly or indirectly to solve a problem. A recursive function must have a base case to terminate the recursive calls and prevent infinite recursion. Here's a simple example of a recursive function to calculate the factorial of a number: public class RecursionExample { public static void main(String[] args) { int number = 5; int result = factorial(...