0
# TLS and SSL Configuration
1
2
Comprehensive TLS/SSL configuration providers for client authentication and server certificate validation. Includes file-based and system property-based key manager providers, supporting various keystore formats and authentication scenarios.
3
4
## Capabilities
5
6
### TlsKeyManagersProvider
7
8
Functional interface for providing KeyManagers used in client TLS authentication. Implementations supply the key managers that contain client certificates and private keys.
9
10
```java { .api }
11
/**
12
* Provider for KeyManagers used in client TLS authentication.
13
* KeyManagers contain the client certificates and private keys used
14
* for mutual TLS authentication with servers.
15
*/
16
@FunctionalInterface
17
public interface TlsKeyManagersProvider {
18
/**
19
* Provide key managers for TLS client authentication
20
* @return Array of KeyManagers, or null if no client authentication is needed
21
*/
22
KeyManager[] keyManagers();
23
24
/**
25
* Provider that returns null (no client authentication)
26
* @return TlsKeyManagersProvider that provides no key managers
27
*/
28
static TlsKeyManagersProvider noneProvider();
29
}
30
```
31
32
**Usage Example:**
33
34
```java
35
// Custom key manager provider
36
TlsKeyManagersProvider customProvider = () -> {
37
try {
38
KeyStore keyStore = loadClientKeyStore();
39
KeyManagerFactory factory = KeyManagerFactory.getInstance("SunX509");
40
factory.init(keyStore, "keystore-password".toCharArray());
41
return factory.getKeyManagers();
42
} catch (Exception e) {
43
throw new RuntimeException("Failed to load client key managers", e);
44
}
45
};
46
47
// No client authentication
48
TlsKeyManagersProvider noAuth = TlsKeyManagersProvider.noneProvider();
49
50
// Using with HTTP client builder
51
MyHttpClient.Builder builder = MyHttpClient.builder()
52
.tlsKeyManagersProvider(customProvider);
53
```
54
55
### FileStoreTlsKeyManagersProvider
56
57
Provider that loads key managers from a file-based keystore. Supports various keystore formats including JKS, PKCS12, and others.
58
59
```java { .api }
60
/**
61
* Loads key managers from a file-based key store.
62
* Supports standard Java keystore formats (JKS, PKCS12, etc.).
63
*/
64
public final class FileStoreTlsKeyManagersProvider extends AbstractFileStoreTlsKeyManagersProvider {
65
/**
66
* Load key managers from the configured keystore file
67
* @return Array of KeyManagers loaded from the file store
68
*/
69
@Override
70
public KeyManager[] keyManagers();
71
72
/**
73
* Create a file store provider from keystore file
74
* @param path Path to the keystore file
75
* @param type Keystore type (e.g., "JKS", "PKCS12")
76
* @param password Password for the keystore
77
* @return FileStoreTlsKeyManagersProvider instance
78
*/
79
public static FileStoreTlsKeyManagersProvider create(Path path, String type, String password);
80
}
81
```
82
83
**Usage Examples:**
84
85
```java
86
// Load from JKS keystore
87
FileStoreTlsKeyManagersProvider jksProvider = FileStoreTlsKeyManagersProvider.create(
88
Paths.get("/path/to/client.jks"),
89
"JKS",
90
"keystore-password"
91
);
92
93
// Load from PKCS12 keystore
94
FileStoreTlsKeyManagersProvider p12Provider = FileStoreTlsKeyManagersProvider.create(
95
Paths.get("/path/to/client.p12"),
96
"PKCS12",
97
"keystore-password"
98
);
99
100
// Using with HTTP client
101
SdkHttpClient client = httpClientBuilder
102
.tlsKeyManagersProvider(jksProvider)
103
.build();
104
105
// Load from environment-specified location
106
String keystorePath = System.getenv("CLIENT_KEYSTORE_PATH");
107
String keystorePass = System.getenv("CLIENT_KEYSTORE_PASSWORD");
108
109
if (keystorePath != null && keystorePass != null) {
110
FileStoreTlsKeyManagersProvider envProvider = FileStoreTlsKeyManagersProvider.create(
111
Paths.get(keystorePath),
112
"PKCS12", // or detect from file extension
113
keystorePass
114
);
115
clientBuilder.tlsKeyManagersProvider(envProvider);
116
}
117
```
118
119
### SystemPropertyTlsKeyManagersProvider
120
121
Provider that loads key managers from standard JSSE system properties. Uses the same properties that the JVM uses for default SSL context configuration.
122
123
```java { .api }
124
/**
125
* Loads key managers from standard JSSE system properties.
126
* Uses javax.net.ssl.keyStore, javax.net.ssl.keyStorePassword,
127
* and javax.net.ssl.keyStoreType system properties.
128
*/
129
public final class SystemPropertyTlsKeyManagersProvider extends AbstractFileStoreTlsKeyManagersProvider {
130
/**
131
* Load key managers from system properties
132
* @return Array of KeyManagers loaded from system property configuration
133
*/
134
@Override
135
public KeyManager[] keyManagers();
136
137
/**
138
* Create a system property provider
139
* @return SystemPropertyTlsKeyManagersProvider instance
140
*/
141
public static SystemPropertyTlsKeyManagersProvider create();
142
}
143
```
144
145
**Usage Example:**
146
147
```java
148
// Using system properties
149
SystemPropertyTlsKeyManagersProvider sysProvider = SystemPropertyTlsKeyManagersProvider.create();
150
151
// The provider will read these system properties:
152
// -Djavax.net.ssl.keyStore=/path/to/client.jks
153
// -Djavax.net.ssl.keyStorePassword=password
154
// -Djavax.net.ssl.keyStoreType=JKS
155
156
// Using with HTTP client
157
SdkHttpClient client = httpClientBuilder
158
.tlsKeyManagersProvider(sysProvider)
159
.build();
160
161
// Command line example:
162
// java -Djavax.net.ssl.keyStore=/etc/ssl/client.p12 \
163
// -Djavax.net.ssl.keyStorePassword=secret \
164
// -Djavax.net.ssl.keyStoreType=PKCS12 \
165
// MyApplication
166
```
167
168
### TlsTrustManagersProvider
169
170
Functional interface for providing TrustManagers used in server certificate validation. Implementations supply trust managers that validate server certificates.
171
172
```java { .api }
173
/**
174
* Provider for TrustManagers used in server certificate validation.
175
* TrustManagers determine which server certificates to trust during
176
* TLS handshake.
177
*/
178
@FunctionalInterface
179
public interface TlsTrustManagersProvider {
180
/**
181
* Provide trust managers for server certificate validation
182
* @return Array of TrustManagers, or null to use system default trust store
183
*/
184
TrustManager[] trustManagers();
185
}
186
```
187
188
**Usage Examples:**
189
190
```java
191
// Custom trust store
192
TlsTrustManagersProvider customTrust = () -> {
193
try {
194
KeyStore trustStore = loadCustomTrustStore();
195
TrustManagerFactory factory = TrustManagerFactory.getInstance("SunX509");
196
factory.init(trustStore);
197
return factory.getTrustManagers();
198
} catch (Exception e) {
199
throw new RuntimeException("Failed to load trust managers", e);
200
}
201
};
202
203
// Trust all certificates (DANGEROUS - for testing only)
204
TlsTrustManagersProvider trustAll = () -> new TrustManager[] {
205
new X509TrustManager() {
206
@Override
207
public void checkClientTrusted(X509Certificate[] chain, String authType) {
208
// Accept all
209
}
210
211
@Override
212
public void checkServerTrusted(X509Certificate[] chain, String authType) {
213
// Accept all
214
}
215
216
@Override
217
public X509Certificate[] getAcceptedIssuers() {
218
return new X509Certificate[0];
219
}
220
}
221
};
222
223
// System default trust store
224
TlsTrustManagersProvider systemDefault = () -> null; // Uses system default
225
```
226
227
## Configuration Patterns
228
229
### Mutual TLS Authentication
230
231
Complete setup for mutual TLS (client certificate authentication):
232
233
```java
234
// Load client certificate and private key
235
FileStoreTlsKeyManagersProvider keyProvider = FileStoreTlsKeyManagersProvider.create(
236
Paths.get("/etc/ssl/private/client.p12"),
237
"PKCS12",
238
System.getenv("CLIENT_CERT_PASSWORD")
239
);
240
241
// Load custom CA certificates for server validation
242
TlsTrustManagersProvider trustProvider = () -> {
243
try {
244
KeyStore trustStore = KeyStore.getInstance("JKS");
245
try (InputStream is = Files.newInputStream(Paths.get("/etc/ssl/ca-bundle.jks"))) {
246
trustStore.load(is, "truststore-password".toCharArray());
247
}
248
249
TrustManagerFactory factory = TrustManagerFactory.getInstance("SunX509");
250
factory.init(trustStore);
251
return factory.getTrustManagers();
252
} catch (Exception e) {
253
throw new RuntimeException("Failed to load trust store", e);
254
}
255
};
256
257
// Configure HTTP client with mutual TLS
258
SdkHttpClient client = httpClientBuilder
259
.tlsKeyManagersProvider(keyProvider)
260
.tlsTrustManagersProvider(trustProvider)
261
.build();
262
```
263
264
### Environment-Based Configuration
265
266
Configuration that adapts to deployment environment:
267
268
```java
269
public static TlsKeyManagersProvider createKeyManagerProvider() {
270
// Try system properties first
271
if (System.getProperty("javax.net.ssl.keyStore") != null) {
272
return SystemPropertyTlsKeyManagersProvider.create();
273
}
274
275
// Try environment variables
276
String keystorePath = System.getenv("TLS_KEYSTORE_PATH");
277
String keystorePassword = System.getenv("TLS_KEYSTORE_PASSWORD");
278
String keystoreType = System.getenv("TLS_KEYSTORE_TYPE");
279
280
if (keystorePath != null && keystorePassword != null) {
281
return FileStoreTlsKeyManagersProvider.create(
282
Paths.get(keystorePath),
283
keystoreType != null ? keystoreType : "PKCS12",
284
keystorePassword
285
);
286
}
287
288
// No client authentication
289
return TlsKeyManagersProvider.noneProvider();
290
}
291
292
public static TlsTrustManagersProvider createTrustManagerProvider() {
293
String trustStorePath = System.getenv("TLS_TRUSTSTORE_PATH");
294
String trustStorePassword = System.getenv("TLS_TRUSTSTORE_PASSWORD");
295
296
if (trustStorePath != null) {
297
return () -> {
298
try {
299
KeyStore trustStore = KeyStore.getInstance("JKS");
300
try (InputStream is = Files.newInputStream(Paths.get(trustStorePath))) {
301
trustStore.load(is, trustStorePassword != null ?
302
trustStorePassword.toCharArray() : null);
303
}
304
305
TrustManagerFactory factory = TrustManagerFactory.getInstance("SunX509");
306
factory.init(trustStore);
307
return factory.getTrustManagers();
308
} catch (Exception e) {
309
throw new RuntimeException("Failed to load custom trust store", e);
310
}
311
};
312
}
313
314
// Use system default
315
return () -> null;
316
}
317
```
318
319
### Certificate Validation Strategies
320
321
Different approaches to server certificate validation:
322
323
```java
324
// Strict validation (production)
325
TlsTrustManagersProvider strictValidation = () -> {
326
// Use system default trust store with standard validation
327
return null;
328
};
329
330
// Custom CA validation
331
TlsTrustManagersProvider customCaValidation = () -> {
332
// Load organization-specific CA certificates
333
return loadOrganizationTrustManagers();
334
};
335
336
// Hostname verification bypass (for testing with self-signed certs)
337
TlsTrustManagersProvider lenientValidation = () -> new TrustManager[] {
338
new X509TrustManager() {
339
private final X509TrustManager defaultTrustManager = getDefaultTrustManager();
340
341
@Override
342
public void checkClientTrusted(X509Certificate[] chain, String authType)
343
throws CertificateException {
344
defaultTrustManager.checkClientTrusted(chain, authType);
345
}
346
347
@Override
348
public void checkServerTrusted(X509Certificate[] chain, String authType)
349
throws CertificateException {
350
try {
351
defaultTrustManager.checkServerTrusted(chain, authType);
352
} catch (CertificateException e) {
353
// Log warning but allow self-signed certificates in test environment
354
if (isTestEnvironment()) {
355
logger.warn("Accepting untrusted certificate in test environment", e);
356
} else {
357
throw e;
358
}
359
}
360
}
361
362
@Override
363
public X509Certificate[] getAcceptedIssuers() {
364
return defaultTrustManager.getAcceptedIssuers();
365
}
366
}
367
};
368
```
369
370
## Security Considerations
371
372
### Best Practices
373
374
1. **Never Trust All Certificates in Production**:
375
```java
376
// NEVER do this in production
377
TlsTrustManagersProvider dangerousTrustAll = () -> new TrustManager[] {
378
new X509TrustManager() {
379
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
380
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
381
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
382
}
383
};
384
```
385
386
2. **Secure Password Handling**:
387
```java
388
// Read passwords from secure sources
389
String password = System.getenv("KEYSTORE_PASSWORD"); // Environment variable
390
// Or from secure configuration service
391
// Never hardcode passwords in source code
392
```
393
394
3. **Certificate Rotation Support**:
395
```java
396
// Support certificate updates without restart
397
TlsKeyManagersProvider reloadableProvider = new TlsKeyManagersProvider() {
398
private volatile KeyManager[] cachedKeyManagers;
399
private volatile long lastLoadTime;
400
private final long reloadInterval = Duration.ofHours(1).toMillis();
401
402
@Override
403
public KeyManager[] keyManagers() {
404
long now = System.currentTimeMillis();
405
if (cachedKeyManagers == null || (now - lastLoadTime) > reloadInterval) {
406
synchronized (this) {
407
if (cachedKeyManagers == null || (now - lastLoadTime) > reloadInterval) {
408
cachedKeyManagers = loadKeyManagers();
409
lastLoadTime = now;
410
}
411
}
412
}
413
return cachedKeyManagers;
414
}
415
};
416
```
417
418
4. **Error Handling**:
419
```java
420
TlsKeyManagersProvider robustProvider = () -> {
421
try {
422
return loadKeyManagers();
423
} catch (Exception e) {
424
// Log error with sufficient detail for debugging
425
logger.error("Failed to load TLS key managers from {}", keystorePath, e);
426
427
// Decide whether to fail fast or fall back
428
if (isClientAuthRequired()) {
429
throw new RuntimeException("Client authentication required but key managers unavailable", e);
430
} else {
431
logger.warn("Proceeding without client authentication");
432
return null;
433
}
434
}
435
};
436
```
437
438
### Keystore Format Support
439
440
The SPI supports various keystore formats:
441
442
- **JKS**: Java KeyStore (legacy format)
443
- **PKCS12**: Standard format (.p12, .pfx files)
444
- **JCEKS**: Java Cryptography Extension KeyStore
445
- **BKS**: Bouncy Castle KeyStore
446
- **UBER**: Bouncy Castle UBER KeyStore
447
448
Example format detection:
449
450
```java
451
public static String detectKeystoreType(Path keystorePath) {
452
String filename = keystorePath.getFileName().toString().toLowerCase();
453
if (filename.endsWith(".p12") || filename.endsWith(".pfx")) {
454
return "PKCS12";
455
} else if (filename.endsWith(".jks")) {
456
return "JKS";
457
} else if (filename.endsWith(".jceks")) {
458
return "JCEKS";
459
} else {
460
// Default to PKCS12 for modern compatibility
461
return "PKCS12";
462
}
463
}
464
```