1 // ========================================================================
2 // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14 package org.eclipse.jetty.server.ssl;
15
16 import java.io.IOException;
17 import java.nio.channels.SelectionKey;
18 import java.nio.channels.SocketChannel;
19 import javax.net.ssl.SSLContext;
20 import javax.net.ssl.SSLEngine;
21 import javax.net.ssl.SSLSession;
22 import javax.net.ssl.SSLSocket;
23
24 import org.eclipse.jetty.http.HttpParser;
25 import org.eclipse.jetty.http.HttpSchemes;
26 import org.eclipse.jetty.http.ssl.SslContextFactory;
27 import org.eclipse.jetty.io.Buffers;
28 import org.eclipse.jetty.io.Buffers.Type;
29 import org.eclipse.jetty.io.BuffersFactory;
30 import org.eclipse.jetty.io.Connection;
31 import org.eclipse.jetty.io.EndPoint;
32 import org.eclipse.jetty.io.bio.SocketEndPoint;
33 import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
34 import org.eclipse.jetty.io.nio.SelectorManager.SelectSet;
35 import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
36 import org.eclipse.jetty.server.HttpConnection;
37 import org.eclipse.jetty.server.Request;
38 import org.eclipse.jetty.server.nio.SelectChannelConnector;
39 import org.eclipse.jetty.util.log.Log;
40
41 /* ------------------------------------------------------------ */
42 /**
43 * SslSelectChannelConnector.
44 *
45 * @org.apache.xbean.XBean element="sslConnector" description="Creates an NIO ssl connector"
46 */
47 public class SslSelectChannelConnector extends SelectChannelConnector implements SslConnector
48 {
49 private final SslContextFactory _sslContextFactory;
50 private Buffers _sslBuffers;
51
52 /* ------------------------------------------------------------ */
53 public SslSelectChannelConnector()
54 {
55 this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
56 }
57
58 /* ------------------------------------------------------------ */
59 public SslSelectChannelConnector(SslContextFactory sslContextFactory)
60 {
61 _sslContextFactory = sslContextFactory;
62 setUseDirectBuffers(false);
63 }
64
65 /* ------------------------------------------------------------ */
66 /**
67 * Allow the Listener a chance to customise the request. before the server
68 * does its stuff. <br>
69 * This allows the required attributes to be set for SSL requests. <br>
70 * The requirements of the Servlet specs are:
71 * <ul>
72 * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
73 * String (since Servlet Spec 3.0).</li>
74 * <li> an attribute named "javax.servlet.request.cipher_suite" of type
75 * String.</li>
76 * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
77 * <li> an attribute named "javax.servlet.request.X509Certificate" of type
78 * java.security.cert.X509Certificate[]. This is an array of objects of type
79 * X509Certificate, the order of this array is defined as being in ascending
80 * order of trust. The first certificate in the chain is the one set by the
81 * client, the next is the one used to authenticate the first, and so on.
82 * </li>
83 * </ul>
84 *
85 * @param endpoint
86 * The Socket the request arrived on. This should be a
87 * {@link SocketEndPoint} wrapping a {@link SSLSocket}.
88 * @param request
89 * HttpRequest to be customised.
90 */
91 @Override
92 public void customize(EndPoint endpoint, Request request) throws IOException
93 {
94 request.setScheme(HttpSchemes.HTTPS);
95 super.customize(endpoint,request);
96
97 SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint;
98 SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine();
99 SSLSession sslSession=sslEngine.getSession();
100
101 SslCertificates.customize(sslSession,endpoint,request);
102 }
103
104 /* ------------------------------------------------------------ */
105 /**
106 * @return True if SSL re-negotiation is allowed (default false)
107 * @deprecated
108 */
109 @Deprecated
110 public boolean isAllowRenegotiate()
111 {
112 return _sslContextFactory.isAllowRenegotiate();
113 }
114
115 /* ------------------------------------------------------------ */
116 /**
117 * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
118 * a vulnerability in SSL/TLS with re-negotiation. If your JVM
119 * does not have CVE-2009-3555 fixed, then re-negotiation should
120 * not be allowed. CVE-2009-3555 was fixed in Sun java 1.6 with a ban
121 * of renegotiate in u19 and with RFC5746 in u22.
122 * @param allowRenegotiate true if re-negotiation is allowed (default false)
123 * @deprecated
124 */
125 @Deprecated
126 public void setAllowRenegotiate(boolean allowRenegotiate)
127 {
128 _sslContextFactory.setAllowRenegotiate(allowRenegotiate);
129 }
130
131 /* ------------------------------------------------------------ */
132 /**
133 * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
134 * @deprecated
135 */
136 @Deprecated
137 public String[] getExcludeCipherSuites()
138 {
139 return _sslContextFactory.getExcludeCipherSuites();
140 }
141
142 /* ------------------------------------------------------------ */
143 /**
144 * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
145 * @deprecated
146 */
147 @Deprecated
148 public void setExcludeCipherSuites(String[] cipherSuites)
149 {
150 _sslContextFactory.setExcludeCipherSuites(cipherSuites);
151 }
152
153 /* ------------------------------------------------------------ */
154 /**
155 * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
156 * @deprecated
157 */
158 @Deprecated
159 public String[] getIncludeCipherSuites()
160 {
161 return _sslContextFactory.getIncludeCipherSuites();
162 }
163
164 /* ------------------------------------------------------------ */
165 /**
166 * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
167 * @deprecated
168 */
169 @Deprecated
170 public void setIncludeCipherSuites(String[] cipherSuites)
171 {
172 _sslContextFactory.setIncludeCipherSuites(cipherSuites);
173 }
174
175 /* ------------------------------------------------------------ */
176 /**
177 * @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String)
178 * @deprecated
179 */
180 @Deprecated
181 public void setPassword(String password)
182 {
183 _sslContextFactory.setKeyStorePassword(password);
184 }
185
186 /* ------------------------------------------------------------ */
187 /**
188 * @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String)
189 * @deprecated
190 */
191 @Deprecated
192 public void setTrustPassword(String password)
193 {
194 _sslContextFactory.setTrustStorePassword(password);
195 }
196
197 /* ------------------------------------------------------------ */
198 /**
199 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeyPassword(java.lang.String)
200 * @deprecated
201 */
202 @Deprecated
203 public void setKeyPassword(String password)
204 {
205 _sslContextFactory.setKeyManagerPassword(password);
206 }
207
208 /* ------------------------------------------------------------ */
209 /**
210 * Unsupported.
211 *
212 * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
213 * @deprecated
214 */
215 @Deprecated
216 public String getAlgorithm()
217 {
218 throw new UnsupportedOperationException();
219 }
220
221 /* ------------------------------------------------------------ */
222 /**
223 * Unsupported.
224 *
225 * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
226 * @deprecated
227 */
228 @Deprecated
229 public void setAlgorithm(String algorithm)
230 {
231 throw new UnsupportedOperationException();
232 }
233
234 /* ------------------------------------------------------------ */
235 /**
236 * @see org.eclipse.jetty.server.ssl.SslConnector#getProtocol()
237 * @deprecated
238 */
239 @Deprecated
240 public String getProtocol()
241 {
242 return _sslContextFactory.getProtocol();
243 }
244
245 /* ------------------------------------------------------------ */
246 /**
247 * @see org.eclipse.jetty.server.ssl.SslConnector#setProtocol(java.lang.String)
248 * @deprecated
249 */
250 @Deprecated
251 public void setProtocol(String protocol)
252 {
253 _sslContextFactory.setProtocol(protocol);
254 }
255
256 /* ------------------------------------------------------------ */
257 /**
258 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystore(java.lang.String)
259 * @deprecated
260 */
261 @Deprecated
262 public void setKeystore(String keystore)
263 {
264 _sslContextFactory.setKeyStore(keystore);
265 }
266
267 /* ------------------------------------------------------------ */
268 /**
269 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystore()
270 * @deprecated
271 */
272 @Deprecated
273 public String getKeystore()
274 {
275 return _sslContextFactory.getKeyStore();
276 }
277
278 /* ------------------------------------------------------------ */
279 /**
280 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystoreType()
281 * @deprecated
282 */
283 @Deprecated
284 public String getKeystoreType()
285 {
286 return _sslContextFactory.getKeyStoreType();
287 }
288
289 /* ------------------------------------------------------------ */
290 /**
291 * @see org.eclipse.jetty.server.ssl.SslConnector#getNeedClientAuth()
292 * @deprecated
293 */
294 @Deprecated
295 public boolean getNeedClientAuth()
296 {
297 return _sslContextFactory.getNeedClientAuth();
298 }
299
300 /* ------------------------------------------------------------ */
301 /**
302 * @see org.eclipse.jetty.server.ssl.SslConnector#getWantClientAuth()
303 * @deprecated
304 */
305 @Deprecated
306 public boolean getWantClientAuth()
307 {
308 return _sslContextFactory.getWantClientAuth();
309 }
310
311 /* ------------------------------------------------------------ */
312 /**
313 * @see org.eclipse.jetty.server.ssl.SslConnector#setNeedClientAuth(boolean)
314 * @deprecated
315 */
316 @Deprecated
317 public void setNeedClientAuth(boolean needClientAuth)
318 {
319 _sslContextFactory.setNeedClientAuth(needClientAuth);
320 }
321
322 /* ------------------------------------------------------------ */
323 /**
324 * @see org.eclipse.jetty.server.ssl.SslConnector#setWantClientAuth(boolean)
325 * @deprecated
326 */
327 @Deprecated
328 public void setWantClientAuth(boolean wantClientAuth)
329 {
330 _sslContextFactory.setWantClientAuth(wantClientAuth);
331 }
332
333 /* ------------------------------------------------------------ */
334 /**
335 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystoreType(java.lang.String)
336 * @deprecated
337 */
338 @Deprecated
339 public void setKeystoreType(String keystoreType)
340 {
341 _sslContextFactory.setKeyStoreType(keystoreType);
342 }
343
344 /* ------------------------------------------------------------ */
345 /**
346 * @see org.eclipse.jetty.server.ssl.SslConnector#getProvider()
347 * @deprecated
348 */
349 @Deprecated
350 public String getProvider()
351 {
352 return _sslContextFactory.getProvider();
353 }
354
355 /* ------------------------------------------------------------ */
356 /**
357 * @see org.eclipse.jetty.server.ssl.SslConnector#getSecureRandomAlgorithm()
358 * @deprecated
359 */
360 @Deprecated
361 public String getSecureRandomAlgorithm()
362 {
363 return _sslContextFactory.getSecureRandomAlgorithm();
364 }
365
366 /* ------------------------------------------------------------ */
367 /**
368 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslKeyManagerFactoryAlgorithm()
369 * @deprecated
370 */
371 @Deprecated
372 public String getSslKeyManagerFactoryAlgorithm()
373 {
374 return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
375 }
376
377 /* ------------------------------------------------------------ */
378 /**
379 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslTrustManagerFactoryAlgorithm()
380 * @deprecated
381 */
382 @Deprecated
383 public String getSslTrustManagerFactoryAlgorithm()
384 {
385 return _sslContextFactory.getTrustManagerFactoryAlgorithm();
386 }
387
388 /* ------------------------------------------------------------ */
389 /**
390 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststore()
391 * @deprecated
392 */
393 @Deprecated
394 public String getTruststore()
395 {
396 return _sslContextFactory.getTrustStore();
397 }
398
399 /* ------------------------------------------------------------ */
400 /**
401 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststoreType()
402 * @deprecated
403 */
404 @Deprecated
405 public String getTruststoreType()
406 {
407 return _sslContextFactory.getTrustStoreType();
408 }
409
410 /* ------------------------------------------------------------ */
411 /**
412 * @see org.eclipse.jetty.server.ssl.SslConnector#setProvider(java.lang.String)
413 * @deprecated
414 */
415 @Deprecated
416 public void setProvider(String provider)
417 {
418 _sslContextFactory.setProvider(provider);
419 }
420
421 /* ------------------------------------------------------------ */
422 /**
423 * @see org.eclipse.jetty.server.ssl.SslConnector#setSecureRandomAlgorithm(java.lang.String)
424 * @deprecated
425 */
426 @Deprecated
427 public void setSecureRandomAlgorithm(String algorithm)
428 {
429 _sslContextFactory.setSecureRandomAlgorithm(algorithm);
430 }
431
432 /* ------------------------------------------------------------ */
433 /**
434 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslKeyManagerFactoryAlgorithm(java.lang.String)
435 * @deprecated
436 */
437 @Deprecated
438 public void setSslKeyManagerFactoryAlgorithm(String algorithm)
439 {
440 _sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
441 }
442
443 /* ------------------------------------------------------------ */
444 /**
445 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String)
446 * @deprecated
447 */
448 @Deprecated
449 public void setSslTrustManagerFactoryAlgorithm(String algorithm)
450 {
451 _sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
452 }
453
454 /* ------------------------------------------------------------ */
455 /**
456 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststore(java.lang.String)
457 * @deprecated
458 */
459 @Deprecated
460 public void setTruststore(String truststore)
461 {
462 _sslContextFactory.setTrustStore(truststore);
463 }
464
465 /* ------------------------------------------------------------ */
466 /**
467 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String)
468 * @deprecated
469 */
470 @Deprecated
471 public void setTruststoreType(String truststoreType)
472 {
473 _sslContextFactory.setTrustStoreType(truststoreType);
474 }
475
476 /* ------------------------------------------------------------ */
477 /**
478 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
479 * @deprecated
480 */
481 @Deprecated
482 public void setSslContext(SSLContext sslContext)
483 {
484 _sslContextFactory.setSslContext(sslContext);
485 }
486
487 /* ------------------------------------------------------------ */
488 /**
489 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
490 * @deprecated
491 */
492 @Deprecated
493 public SSLContext getSslContext()
494 {
495 return _sslContextFactory.getSslContext();
496 }
497
498 /* ------------------------------------------------------------ */
499 /**
500 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslContextFactory()
501 */
502 public SslContextFactory getSslContextFactory()
503 {
504 return _sslContextFactory;
505 }
506
507 /* ------------------------------------------------------------ */
508 /**
509 * By default, we're confidential, given we speak SSL. But, if we've been
510 * told about an confidential port, and said port is not our port, then
511 * we're not. This allows separation of listeners providing INTEGRAL versus
512 * CONFIDENTIAL constraints, such as one SSL listener configured to require
513 * client certs providing CONFIDENTIAL, whereas another SSL listener not
514 * requiring client certs providing mere INTEGRAL constraints.
515 */
516 @Override
517 public boolean isConfidential(Request request)
518 {
519 final int confidentialPort=getConfidentialPort();
520 return confidentialPort==0||confidentialPort==request.getServerPort();
521 }
522
523 /* ------------------------------------------------------------ */
524 /**
525 * By default, we're integral, given we speak SSL. But, if we've been told
526 * about an integral port, and said port is not our port, then we're not.
527 * This allows separation of listeners providing INTEGRAL versus
528 * CONFIDENTIAL constraints, such as one SSL listener configured to require
529 * client certs providing CONFIDENTIAL, whereas another SSL listener not
530 * requiring client certs providing mere INTEGRAL constraints.
531 */
532 @Override
533 public boolean isIntegral(Request request)
534 {
535 final int integralPort=getIntegralPort();
536 return integralPort==0||integralPort==request.getServerPort();
537 }
538
539 /* ------------------------------------------------------------------------------- */
540 @Override
541 protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
542 {
543 SSLEngine engine = createSSLEngine(channel);
544 SslSelectChannelEndPoint endp = new SslSelectChannelEndPoint(_sslBuffers,channel,selectSet,key,engine, SslSelectChannelConnector.this._maxIdleTime);
545 endp.setAllowRenegotiate(_sslContextFactory.isAllowRenegotiate());
546 return endp;
547 }
548
549 /* ------------------------------------------------------------------------------- */
550 @Override
551 protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
552 {
553 HttpConnection connection=(HttpConnection)super.newConnection(channel,endpoint);
554 ((HttpParser)connection.getParser()).setForceContentBuffer(true);
555 return connection;
556 }
557
558 /* ------------------------------------------------------------ */
559 /**
560 * @param channel A channel which if passed is used as to extract remote
561 * host and port for the purposes of SSL session caching
562 * @return A SSLEngine for a new or cached SSL Session
563 * @throws IOException if the SSLEngine cannot be created
564 */
565 protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException
566 {
567 SSLEngine engine;
568 if (channel != null && _sslContextFactory.isSessionCachingEnabled())
569 {
570 String peerHost = channel.socket().getInetAddress().getHostAddress();
571 int peerPort = channel.socket().getPort();
572 engine = _sslContextFactory.getSslContext().createSSLEngine(peerHost, peerPort);
573 }
574 else
575 {
576 engine = _sslContextFactory.getSslContext().createSSLEngine();
577 }
578 customizeEngine(engine);
579 return engine;
580 }
581
582 /* ------------------------------------------------------------ */
583 private void customizeEngine(SSLEngine engine)
584 {
585 engine.setUseClientMode(false);
586
587 if (_sslContextFactory.getWantClientAuth())
588 engine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
589 if (_sslContextFactory.getNeedClientAuth())
590 engine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
591
592 engine.setEnabledCipherSuites(
593 _sslContextFactory.selectCipherSuites(engine.getEnabledCipherSuites(),
594 engine.getSupportedCipherSuites()));
595 }
596
597 /* ------------------------------------------------------------ */
598 /**
599 * @see org.eclipse.jetty.server.nio.SelectChannelConnector#doStart()
600 */
601 @Override
602 protected void doStart() throws Exception
603 {
604 if (!_sslContextFactory.checkConfig())
605 {
606 throw new IllegalStateException("SSL context is not configured correctly.");
607 }
608
609 _sslContextFactory.start();
610
611 SSLEngine sslEngine = _sslContextFactory.getSslContext().createSSLEngine();
612
613 sslEngine.setUseClientMode(false);
614 sslEngine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
615 sslEngine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
616
617 sslEngine.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
618 sslEngine.getEnabledCipherSuites(),
619 sslEngine.getSupportedCipherSuites()));
620
621 SSLSession sslSession = sslEngine.getSession();
622
623 _sslBuffers = BuffersFactory.newBuffers(
624 getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,sslSession.getApplicationBufferSize(),
625 getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,sslSession.getApplicationBufferSize(),
626 getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,getMaxBuffers()
627 );
628
629 if (getRequestHeaderSize()<sslSession.getApplicationBufferSize())
630 setRequestHeaderSize(sslSession.getApplicationBufferSize());
631 if (getRequestBufferSize()<sslSession.getApplicationBufferSize())
632 setRequestBufferSize(sslSession.getApplicationBufferSize());
633
634 super.doStart();
635 }
636
637 /* ------------------------------------------------------------ */
638 /**
639 * @see org.eclipse.jetty.server.nio.SelectChannelConnector#doStop()
640 */
641 @Override
642 protected void doStop() throws Exception
643 {
644 _sslContextFactory.stop();
645 _sslBuffers=null;
646 super.doStop();
647 }
648
649 /* ------------------------------------------------------------ */
650 /**
651 * @return SSL buffers
652 */
653 public Buffers getSslBuffers()
654 {
655 return _sslBuffers;
656 }
657 }