Skip to main content

SSL/TLS Configuration

Advanced SSL/TLS setup for production-grade secure socket communication.

Production SSL Setup

Using Real Certificates

In production, use certificates from a trusted Certificate Authority (CA):

@Component
public class ProductionSSLConfig implements SSLFactoryLoader {

@Env("KEYSTORE_PATH")
private String keystorePath;

@Env("KEYSTORE_PASSWORD")
private String keystorePassword;

@Env("KEY_PASSWORD")
private String keyPassword;

@Override
public SSLServerSocketFactory getSSLServerSocketFactory() throws Exception {
// Load keystore with production certificate
KeyStore keyStore = KeyStore.getInstance("JKS");
try (FileInputStream fis = new FileInputStream(keystorePath)) {
keyStore.load(fis, keystorePassword.toCharArray());
}

// Initialize Key Manager
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm()
);
kmf.init(keyStore, keyPassword.toCharArray());

// Configure SSL Context with TLS 1.2+
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());

SSLServerSocketFactory factory = sslContext.getServerSocketFactory();

// Configure protocols and cipher suites
SSLParameters params = sslContext.getDefaultSSLParameters();
params.setProtocols(new String[]{"TLSv1.2", "TLSv1.3"});
params.setCipherSuites(getSecureCipherSuites());

return factory;
}

private String[] getSecureCipherSuites() {
return new String[]{
"TLS_AES_256_GCM_SHA384",
"TLS_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
};
}
}

Mutual TLS (mTLS)

Require client certificates for authentication:

@Component
public class MutualTLSConfig implements SSLFactoryLoader {

@Override
public SSLServerSocketFactory getSSLServerSocketFactory() throws Exception {
// Load server keystore
KeyStore keyStore = loadKeyStore("server-keystore.jks", "password");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyStore, "password".toCharArray());

// Load truststore (contains trusted client certificates)
KeyStore trustStore = loadKeyStore("client-truststore.jks", "password");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustStore);

// Initialize SSL Context
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(
kmf.getKeyManagers(),
tmf.getTrustManagers(),
new SecureRandom()
);

SSLServerSocketFactory factory = sslContext.getServerSocketFactory();

// Enable client authentication
SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(8443);
serverSocket.setNeedClientAuth(true); // Require client cert

return factory;
}

private KeyStore loadKeyStore(String path, String password) throws Exception {
KeyStore ks = KeyStore.getInstance("JKS");
try (FileInputStream fis = new FileInputStream(path)) {
ks.load(fis, password.toCharArray());
}
return ks;
}
}

Client SSL Configuration

Configure the client to trust the server:

public class ClientSSLConfig implements SSLSecuritySocketLoader {

@Override
public SSLSocketFactory getSSLSocketFactory() throws Exception {
// Load truststore containing server certificate
KeyStore trustStore = KeyStore.getInstance("JKS");
try (FileInputStream fis = new FileInputStream("truststore.jks")) {
trustStore.load(fis, "password".toCharArray());
}

// Trust Manager
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()
);
tmf.init(trustStore);

// SSL Context
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());

return sslContext.getSocketFactory();
}
}

Certificate Management

Generating Production Certificates

Use Let's Encrypt or purchase from a CA. Convert to JKS:

# Convert PEM to PKCS12
openssl pkcs12 -export \
-in certificate.crt \
-inkey private.key \
-out keystore.p12 \
-name server

# Convert PKCS12 to JKS
keytool -importkeystore \
-srckeystore keystore.p12 \
-srcstoretype PKCS12 \
-destkeystore keystore.jks \
-deststoretype JKS

Certificate Rotation

Implement automatic certificate renewal:

@Component
public class CertificateRotationService {

@Scheduled(cron = "0 0 2 * * ?") // Daily at 2 AM
public void checkCertificateExpiry() {
KeyStore keyStore = loadKeyStore();
X509Certificate cert = (X509Certificate) keyStore.getCertificate("server");

Date expiryDate = cert.getNotAfter();
long daysUntilExpiry = ChronoUnit.DAYS.between(
Instant.now(),
expiryDate.toInstant()
);

if (daysUntilExpiry < 30) {
System.err.println("WARNING: Certificate expires in " + daysUntilExpiry + " days!");
renewCertificate();
}
}

private void renewCertificate() {
// Implement certificate renewal logic
// - Request new certificate from CA
// - Update keystore
// - Reload SSL context (may require server restart)
}
}

Security Best Practices

1. Disable Weak Protocols

SSLParameters params = sslContext.getDefaultSSLParameters();
params.setProtocols(new String[]{"TLSv1.2", "TLSv1.3"}); // No TLS 1.0/1.1!

2. Disable Weak Cipher Suites

String[] secureCiphers = {
"TLS_AES_256_GCM_SHA384",
"TLS_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
};
params.setCipherSuites(secureCiphers);

3. Enable OCSP Stapling

System.setProperty("jdk.tls.client.enableStatusRequestExtension", "true");
System.setProperty("com.sun.net.ssl.checkRevocation", "true");

4. Use Strong Key Sizes

  • RSA: Minimum 2048 bits (recommend 4096 for long-term)
  • ECDSA: Minimum 256 bits

5. Secure Key Storage

# Restrict keystore file permissions
chmod 600 keystore.jks
chown app-user:app-group keystore.jks

# Never commit keystores to version control
echo "*.jks" >> .gitignore
echo "*.p12" >> .gitignore

Testing SSL Configuration

Verify SSL Handshake

# Test with OpenSSL
openssl s_client -connect localhost:8443 -tls1_3

# Check certificate details
keytool -list -v -keystore keystore.jks

SSL Scanner Tools

# SSL Labs (for public servers)
# https://www.ssllabs.com/ssltest/

# Nmap SSL scan
nmap --script ssl-enum-ciphers -p 8443 localhost

# testssl.sh (comprehensive)
./testssl.sh localhost:8443

Common SSL Issues

Issue: "Certificate Expired"

Solution: Renew certificate and update keystore

# Check expiry date
keytool -list -v -keystore keystore.jks | grep "Valid"

Issue: "Certificate Not Trusted"

Solution: Ensure client truststore contains server certificate or CA certificate

Issue: "SSL Handshake Failed"

Causes:

  1. Protocol mismatch (client uses TLS 1.0, server requires 1.2+)
  2. Cipher suite mismatch
  3. Certificate hostname mismatch

Debug:

System.setProperty("javax.net.debug", "ssl:handshake");

Environment Variables

.env:

# Server keystore
KEYSTORE_PATH=/path/to/keystore.jks
KEYSTORE_PASSWORD=changeit
KEY_PASSWORD=changeit

# Client truststore
TRUSTSTORE_PATH=/path/to/truststore.jks
TRUSTSTORE_PASSWORD=changeit

# SSL protocol
SSL_PROTOCOL=TLSv1.3

Next Steps

👉 Custom Transformers - Add encryption layer 👉 Performance Tuning - Optimize for production 👉 Best Practices - Security guidelines