0
# SSL/TLS Support
1
2
Jetty IO provides comprehensive SSL/TLS support including secure connections, handshake management, and Application Layer Protocol Negotiation (ALPN) for modern protocol negotiation.
3
4
## Capabilities
5
6
### SslConnection
7
8
SSL/TLS connection wrapper that provides encryption layer over an existing EndPoint.
9
10
```java { .api }
11
/**
12
* SSL/TLS connection wrapper providing encryption layer
13
*/
14
class SslConnection extends AbstractConnection implements Connection.UpgradeTo {
15
public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine);
16
public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine, boolean useInputDirectByteBuffers, boolean useOutputDirectByteBuffers);
17
18
// SSL engine access
19
public SSLEngine getSSLEngine();
20
21
// SSL session information
22
public String getProtocol();
23
public String getCipherSuite();
24
public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException;
25
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException;
26
public Principal getLocalPrincipal();
27
28
// Connection state
29
public boolean isHandshaking();
30
public boolean isHandshakeComplete();
31
public boolean isOpen();
32
33
// Buffer configuration
34
public boolean isUseInputDirectByteBuffers();
35
public boolean isUseOutputDirectByteBuffers();
36
public void setUseInputDirectByteBuffers(boolean useInputDirectByteBuffers);
37
public void setUseOutputDirectByteBuffers(boolean useOutputDirectByteBuffers);
38
39
// Renegotiation
40
public void beginHandshake() throws SSLException;
41
public CompletableFuture<Void> handshake();
42
43
// Lifecycle
44
public void onOpen();
45
public void onClose(Throwable cause);
46
public void onFillable();
47
public boolean onIdleExpired(TimeoutException timeoutException);
48
49
// Connection upgrade support
50
public void onUpgradeTo(ByteBuffer prefilled);
51
52
// Statistics
53
public long getBytesIn();
54
public long getBytesOut();
55
public long getEncryptedBytesIn();
56
public long getEncryptedBytesOut();
57
}
58
```
59
60
**Usage Examples:**
61
62
```java
63
// Create SSL connection
64
SSLEngine sslEngine = sslContextFactory.newSSLEngine("example.com", 443);
65
sslEngine.setUseClientMode(true);
66
sslEngine.setWantClientAuth(false);
67
68
SslConnection sslConnection = new SslConnection(
69
byteBufferPool,
70
executor,
71
tcpEndPoint,
72
sslEngine
73
);
74
75
// Configure buffer usage (direct buffers can be more efficient for SSL)
76
sslConnection.setUseInputDirectByteBuffers(true);
77
sslConnection.setUseOutputDirectByteBuffers(true);
78
79
// Perform handshake
80
CompletableFuture<Void> handshakeFuture = sslConnection.handshake();
81
handshakeFuture.thenRun(() -> {
82
System.out.println("SSL handshake completed");
83
System.out.println("Protocol: " + sslConnection.getProtocol());
84
System.out.println("Cipher suite: " + sslConnection.getCipherSuite());
85
86
try {
87
Certificate[] peerCerts = sslConnection.getPeerCertificates();
88
System.out.println("Peer certificate count: " + peerCerts.length);
89
} catch (SSLPeerUnverifiedException e) {
90
System.out.println("Peer certificate not verified");
91
}
92
}).exceptionally(throwable -> {
93
System.err.println("SSL handshake failed: " + throwable.getMessage());
94
return null;
95
});
96
97
// Monitor SSL traffic
98
Timer timer = new Timer();
99
timer.scheduleAtFixedRate(new TimerTask() {
100
@Override
101
public void run() {
102
System.out.printf("SSL Traffic - Plain: %d/%d bytes, Encrypted: %d/%d bytes%n",
103
sslConnection.getBytesIn(), sslConnection.getBytesOut(),
104
sslConnection.getEncryptedBytesIn(), sslConnection.getEncryptedBytesOut());
105
}
106
}, 0, 10000);
107
108
// Manual renegotiation
109
if (sslConnection.isHandshakeComplete() && !sslConnection.isHandshaking()) {
110
try {
111
sslConnection.beginHandshake();
112
System.out.println("SSL renegotiation initiated");
113
} catch (SSLException e) {
114
System.err.println("Failed to initiate renegotiation: " + e.getMessage());
115
}
116
}
117
```
118
119
### SslClientConnectionFactory
120
121
Factory for creating SSL client connections with automatic SSL context configuration.
122
123
```java { .api }
124
/**
125
* Creates SSL client connections
126
*/
127
class SslClientConnectionFactory implements ClientConnectionFactory {
128
public SslClientConnectionFactory(SslContextFactory.Client sslContextFactory, ClientConnectionFactory connectionFactory);
129
public SslClientConnectionFactory(SslContextFactory.Client sslContextFactory, String nextProtocol);
130
131
public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException;
132
public Connection customize(Connection connection, Map<String, Object> context);
133
134
// Configuration
135
public SslContextFactory.Client getSslContextFactory();
136
public ClientConnectionFactory getClientConnectionFactory();
137
public String getNextProtocol();
138
139
// Direct buffer configuration
140
public boolean isDirectBuffersForEncryption();
141
public void setDirectBuffersForEncryption(boolean direct);
142
public boolean isDirectBuffersForDecryption();
143
public void setDirectBuffersForDecryption(boolean direct);
144
}
145
```
146
147
**Usage Examples:**
148
149
```java
150
// SSL context factory configuration
151
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
152
sslContextFactory.setTrustAll(false); // Verify server certificates
153
sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS"); // Enable hostname verification
154
sslContextFactory.setProtocol("TLS"); // Use TLS protocol
155
sslContextFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384");
156
sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA");
157
158
// HTTP/1.1 over SSL
159
ClientConnectionFactory http11Factory = new HttpClientConnectionFactory();
160
SslClientConnectionFactory sslFactory = new SslClientConnectionFactory(sslContextFactory, http11Factory);
161
162
// Direct SSL factory for specific protocol
163
SslClientConnectionFactory directSslFactory = new SslClientConnectionFactory(sslContextFactory, "http/1.1");
164
165
// Configure direct buffers for better performance
166
sslFactory.setDirectBuffersForEncryption(true);
167
sslFactory.setDirectBuffersForDecryption(true);
168
169
// Create SSL connection
170
Map<String, Object> context = new HashMap<>();
171
context.put(ClientConnectionFactory.CLIENT_CONTEXT_KEY, httpClient);
172
context.put(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY, sslContextFactory);
173
174
Connection sslConnection = sslFactory.newConnection(tcpEndPoint, context);
175
176
// Chain multiple factories for protocol layering
177
ClientConnectionFactory http2Factory = new HTTP2ClientConnectionFactory();
178
SslClientConnectionFactory http2SslFactory = new SslClientConnectionFactory(sslContextFactory, http2Factory);
179
180
// ALPN negotiation factory
181
ALPNClientConnectionFactory alpnFactory = new ALPNClientConnectionFactory(
182
executor, http2SslFactory, "h2", "http/1.1");
183
SslClientConnectionFactory alpnSslFactory = new SslClientConnectionFactory(sslContextFactory, alpnFactory);
184
```
185
186
### SslHandshakeListener
187
188
Event listener for monitoring SSL/TLS handshake process and outcomes.
189
190
```java { .api }
191
/**
192
* Listener for SSL handshake events
193
*/
194
interface SslHandshakeListener extends EventListener {
195
/** Called when SSL handshake succeeds */
196
default void handshakeSucceeded(Event event) {}
197
198
/** Called when SSL handshake fails */
199
default void handshakeFailed(Event event, Throwable failure) {}
200
201
class Event {
202
private final SSLEngine sslEngine;
203
204
public Event(SSLEngine sslEngine);
205
206
public SSLEngine getSSLEngine();
207
public String getProtocol();
208
public String getCipherSuite();
209
public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException;
210
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException;
211
public Principal getLocalPrincipal();
212
}
213
}
214
```
215
216
**Usage Examples:**
217
218
```java
219
// SSL handshake monitoring
220
SslHandshakeListener handshakeMonitor = new SslHandshakeListener() {
221
@Override
222
public void handshakeSucceeded(Event event) {
223
System.out.println("SSL handshake succeeded:");
224
System.out.println(" Protocol: " + event.getProtocol());
225
System.out.println(" Cipher: " + event.getCipherSuite());
226
227
try {
228
Certificate[] certs = event.getPeerCertificates();
229
if (certs.length > 0 && certs[0] instanceof X509Certificate) {
230
X509Certificate x509 = (X509Certificate) certs[0];
231
System.out.println(" Subject: " + x509.getSubjectDN());
232
System.out.println(" Issuer: " + x509.getIssuerDN());
233
System.out.println(" Valid until: " + x509.getNotAfter());
234
}
235
} catch (SSLPeerUnverifiedException e) {
236
System.out.println(" Peer not verified: " + e.getMessage());
237
}
238
}
239
240
@Override
241
public void handshakeFailed(Event event, Throwable failure) {
242
System.err.println("SSL handshake failed: " + failure.getMessage());
243
if (failure instanceof SSLException) {
244
SSLException sslEx = (SSLException) failure;
245
System.err.println("SSL error details: " + sslEx.toString());
246
}
247
}
248
};
249
250
// Add listener to SSL context factory
251
sslContextFactory.addEventListener(handshakeMonitor);
252
253
// Certificate validation listener
254
SslHandshakeListener certValidator = new SslHandshakeListener() {
255
@Override
256
public void handshakeSucceeded(Event event) {
257
try {
258
Certificate[] certs = event.getPeerCertificates();
259
validateCertificateChain(certs);
260
} catch (Exception e) {
261
System.err.println("Certificate validation failed: " + e.getMessage());
262
}
263
}
264
265
private void validateCertificateChain(Certificate[] certs) throws Exception {
266
// Custom certificate validation logic
267
if (certs.length == 0) {
268
throw new SSLException("No certificates provided");
269
}
270
271
X509Certificate serverCert = (X509Certificate) certs[0];
272
273
// Check certificate validity period
274
serverCert.checkValidity();
275
276
// Check certificate purpose
277
List<String> extKeyUsage = serverCert.getExtendedKeyUsage();
278
if (extKeyUsage != null && !extKeyUsage.contains("1.3.6.1.5.5.7.3.1")) { // Server authentication
279
throw new SSLException("Certificate not valid for server authentication");
280
}
281
282
System.out.println("Certificate validation passed");
283
}
284
};
285
```
286
287
### ALPNProcessor
288
289
Interface for handling Application Layer Protocol Negotiation (ALPN) during SSL handshake.
290
291
```java { .api }
292
/**
293
* Interface for ALPN (Application Layer Protocol Negotiation) processing
294
*/
295
interface ALPNProcessor {
296
/**
297
* Process ALPN negotiation result
298
* @param sslEngine the SSL engine
299
* @param protocols list of protocols offered by client
300
* @param selected the protocol selected by server
301
*/
302
void process(SSLEngine sslEngine, List<String> protocols, String selected);
303
304
// Server-side ALPN processor
305
abstract class Server implements ALPNProcessor {
306
/** Select protocol from client's list */
307
public abstract String select(List<String> protocols);
308
309
public void process(SSLEngine sslEngine, List<String> protocols, String selected);
310
}
311
312
// Client-side ALPN processor
313
abstract class Client implements ALPNProcessor {
314
private final List<String> protocols;
315
316
protected Client(String... protocols);
317
318
/** Handle selected protocol */
319
public abstract void selected(String protocol);
320
321
public List<String> getProtocols();
322
public void process(SSLEngine sslEngine, List<String> protocols, String selected);
323
}
324
}
325
```
326
327
**ALPN Usage Examples:**
328
329
```java
330
// Server-side ALPN processor
331
ALPNProcessor.Server serverALPN = new ALPNProcessor.Server() {
332
@Override
333
public String select(List<String> protocols) {
334
System.out.println("Client offered protocols: " + protocols);
335
336
// Prefer HTTP/2, fallback to HTTP/1.1
337
if (protocols.contains("h2")) {
338
return "h2";
339
} else if (protocols.contains("http/1.1")) {
340
return "http/1.1";
341
}
342
return null; // No supported protocol
343
}
344
345
@Override
346
public void process(SSLEngine sslEngine, List<String> protocols, String selected) {
347
System.out.println("Selected protocol: " + selected);
348
super.process(sslEngine, protocols, selected);
349
}
350
};
351
352
// Client-side ALPN processor
353
ALPNProcessor.Client clientALPN = new ALPNProcessor.Client("h2", "http/1.1") {
354
@Override
355
public void selected(String protocol) {
356
System.out.println("Server selected protocol: " + protocol);
357
358
switch (protocol) {
359
case "h2":
360
// Configure for HTTP/2
361
configureHTTP2();
362
break;
363
case "http/1.1":
364
// Configure for HTTP/1.1
365
configureHTTP11();
366
break;
367
default:
368
System.err.println("Unexpected protocol selected: " + protocol);
369
}
370
}
371
372
private void configureHTTP2() {
373
System.out.println("Initializing HTTP/2 configuration");
374
// HTTP/2 specific setup
375
}
376
377
private void configureHTTP11() {
378
System.out.println("Initializing HTTP/1.1 configuration");
379
// HTTP/1.1 specific setup
380
}
381
};
382
383
// Register ALPN processors with SSL context factory
384
sslContextFactory.addBean(serverALPN); // Server side
385
sslContextFactory.addBean(clientALPN); // Client side
386
387
// Custom ALPN processor for protocol-specific handling
388
ALPNProcessor customProcessor = new ALPNProcessor() {
389
@Override
390
public void process(SSLEngine sslEngine, List<String> protocols, String selected) {
391
System.out.println("ALPN negotiation completed");
392
System.out.println("Offered: " + protocols);
393
System.out.println("Selected: " + selected);
394
395
// Store selected protocol for later use
396
sslEngine.setHandshakeApplicationProtocolSelector((sslEngine1, protocols1) -> {
397
// Custom protocol selection logic
398
return selectCustomProtocol(protocols1);
399
});
400
}
401
402
private String selectCustomProtocol(List<String> protocols) {
403
// Custom protocol selection algorithm
404
for (String protocol : protocols) {
405
if (protocol.startsWith("custom-")) {
406
return protocol;
407
}
408
}
409
return protocols.isEmpty() ? null : protocols.get(0);
410
}
411
};
412
```
413
414
### SSL Configuration Best Practices
415
416
```java { .api }
417
/**
418
* SSL context factory configuration examples
419
*/
420
class SSLConfigurationExamples {
421
public static SslContextFactory.Client createSecureClient() {
422
SslContextFactory.Client factory = new SslContextFactory.Client();
423
424
// Security settings
425
factory.setTrustAll(false); // Always verify certificates
426
factory.setEndpointIdentificationAlgorithm("HTTPS"); // Enable hostname verification
427
factory.setRenegotiationAllowed(false); // Disable renegotiation for security
428
429
// Protocol configuration
430
factory.setProtocol("TLS");
431
factory.setIncludeProtocols("TLSv1.2", "TLSv1.3");
432
factory.setExcludeProtocols("SSLv2", "SSLv3", "TLSv1", "TLSv1.1");
433
434
// Cipher suite configuration
435
factory.setIncludeCipherSuites(
436
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
437
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
438
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
439
);
440
factory.setExcludeCipherSuites(
441
".*_DES_.*", ".*_RC4_.*", ".*_MD5$", ".*_SHA$"
442
);
443
444
return factory;
445
}
446
447
public static SslContextFactory.Server createSecureServer(Path keystorePath, String keystorePassword) {
448
SslContextFactory.Server factory = new SslContextFactory.Server();
449
450
// Keystore configuration
451
factory.setKeyStorePath(keystorePath.toString());
452
factory.setKeyStorePassword(keystorePassword);
453
factory.setKeyStoreType("PKCS12");
454
455
// Client authentication
456
factory.setWantClientAuth(true); // Request client certificates
457
factory.setNeedClientAuth(false); // But don't require them
458
459
// Security settings
460
factory.setRenegotiationAllowed(false);
461
factory.setSessionCachingEnabled(true);
462
factory.setSessionTimeout(3600); // 1 hour session timeout
463
464
// Protocol and cipher configuration (same as client)
465
factory.setProtocol("TLS");
466
factory.setIncludeProtocols("TLSv1.2", "TLSv1.3");
467
// ... cipher suites as above
468
469
return factory;
470
}
471
}
472
```
473
474
**Configuration Usage:**
475
476
```java
477
// Secure client configuration
478
SslContextFactory.Client clientSSL = SSLConfigurationExamples.createSecureClient();
479
480
// Custom truststore for client
481
clientSSL.setTrustStorePath("/path/to/truststore.p12");
482
clientSSL.setTrustStorePassword("truststore-password");
483
clientSSL.setTrustStoreType("PKCS12");
484
485
// Client certificate authentication
486
clientSSL.setKeyStorePath("/path/to/client-keystore.p12");
487
clientSSL.setKeyStorePassword("client-keystore-password");
488
489
// SNI (Server Name Indication) configuration
490
clientSSL.setSNIMatchers(
491
new SNIMatcher(StandardConstants.SNI_HOST_NAME) {
492
@Override
493
public boolean matches(SNIServerName serverName) {
494
return serverName.getAsciiName().endsWith(".example.com");
495
}
496
}
497
);
498
499
// Start SSL context factory
500
clientSSL.start();
501
502
// Create SSL connection factory
503
ClientConnectionFactory httpFactory = new HttpClientConnectionFactory();
504
SslClientConnectionFactory sslFactory = new SslClientConnectionFactory(clientSSL, httpFactory);
505
```