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:
- Protocol mismatch (client uses TLS 1.0, server requires 1.2+)
- Cipher suite mismatch
- 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