1 // ========================================================================
2 // Copyright (c) 2000-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.net.ServerSocket;
18 import java.net.Socket;
19 import javax.net.ssl.HandshakeCompletedEvent;
20 import javax.net.ssl.HandshakeCompletedListener;
21 import javax.net.ssl.SSLContext;
22 import javax.net.ssl.SSLException;
23 import javax.net.ssl.SSLServerSocket;
24 import javax.net.ssl.SSLSession;
25 import javax.net.ssl.SSLSocket;
26
27 import org.eclipse.jetty.http.HttpSchemes;
28 import org.eclipse.jetty.http.ssl.SslContextFactory;
29 import org.eclipse.jetty.io.EndPoint;
30 import org.eclipse.jetty.io.RuntimeIOException;
31 import org.eclipse.jetty.io.bio.SocketEndPoint;
32 import org.eclipse.jetty.server.Request;
33 import org.eclipse.jetty.server.bio.SocketConnector;
34 import org.eclipse.jetty.util.log.Log;
35 import org.eclipse.jetty.util.log.Logger;
36
37 /* ------------------------------------------------------------ */
38 /**
39 * SSL Socket Connector.
40 *
41 * This specialization of SocketConnector is an abstract listener that can be used as the basis for a
42 * specific JSSE listener.
43 *
44 * The original of this class was heavily based on the work from Court Demas, which in turn is
45 * based on the work from Forge Research. Since JSSE, this class has evolved significantly from
46 * that early work.
47 *
48 * @org.apache.xbean.XBean element="sslSocketConnector" description="Creates an ssl socket connector"
49 *
50 *
51 */
52 public class SslSocketConnector extends SocketConnector implements SslConnector
53 {
54 private static final Logger LOG = Log.getLogger(SslSocketConnector.class);
55
56 private final SslContextFactory _sslContextFactory;
57 private int _handshakeTimeout = 0; //0 means use maxIdleTime
58
59 /* ------------------------------------------------------------ */
60 /**
61 * Constructor.
62 */
63 public SslSocketConnector()
64 {
65 this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
66 }
67
68 /* ------------------------------------------------------------ */
69 public SslSocketConnector(SslContextFactory sslContextFactory)
70 {
71 _sslContextFactory = sslContextFactory;
72 }
73
74 /* ------------------------------------------------------------ */
75 /**
76 * @return True if SSL re-negotiation is allowed (default false)
77 */
78 public boolean isAllowRenegotiate()
79 {
80 return _sslContextFactory.isAllowRenegotiate();
81 }
82
83 /* ------------------------------------------------------------ */
84 /**
85 * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
86 * a vulnerability in SSL/TLS with re-negotiation. If your JVM
87 * does not have CVE-2009-3555 fixed, then re-negotiation should
88 * not be allowed.
89 * @param allowRenegotiate true if re-negotiation is allowed (default false)
90 */
91 public void setAllowRenegotiate(boolean allowRenegotiate)
92 {
93 _sslContextFactory.setAllowRenegotiate(allowRenegotiate);
94 }
95
96 /* ------------------------------------------------------------ */
97 @Override
98 public void accept(int acceptorID)
99 throws IOException, InterruptedException
100 {
101 Socket socket = _serverSocket.accept();
102 configure(socket);
103
104 ConnectorEndPoint connection=new SslConnectorEndPoint(socket);
105 connection.dispatch();
106 }
107
108 /* ------------------------------------------------------------ */
109 @Override
110 protected void configure(Socket socket)
111 throws IOException
112 {
113 super.configure(socket);
114 }
115
116 /* ------------------------------------------------------------ */
117 /**
118 * Allow the Listener a chance to customise the request. before the server does its stuff. <br>
119 * This allows the required attributes to be set for SSL requests. <br>
120 * The requirements of the Servlet specs are:
121 * <ul>
122 * <li> an attribute named "javax.servlet.request.ssl_id" of type String (since Spec 3.0).</li>
123 * <li> an attribute named "javax.servlet.request.cipher_suite" of type String.</li>
124 * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
125 * <li> an attribute named "javax.servlet.request.X509Certificate" of type
126 * java.security.cert.X509Certificate[]. This is an array of objects of type X509Certificate,
127 * the order of this array is defined as being in ascending order of trust. The first
128 * certificate in the chain is the one set by the client, the next is the one used to
129 * authenticate the first, and so on. </li>
130 * </ul>
131 *
132 * @param endpoint The Socket the request arrived on.
133 * This should be a {@link SocketEndPoint} wrapping a {@link SSLSocket}.
134 * @param request HttpRequest to be customised.
135 */
136 @Override
137 public void customize(EndPoint endpoint, Request request)
138 throws IOException
139 {
140 super.customize(endpoint, request);
141 request.setScheme(HttpSchemes.HTTPS);
142
143 SocketEndPoint socket_end_point = (SocketEndPoint)endpoint;
144 SSLSocket sslSocket = (SSLSocket)socket_end_point.getTransport();
145 SSLSession sslSession = sslSocket.getSession();
146
147 SslCertificates.customize(sslSession,endpoint,request);
148 }
149
150 /* ------------------------------------------------------------ */
151 /**
152 * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
153 * @deprecated
154 */
155 @Deprecated
156 public String[] getExcludeCipherSuites() {
157 return _sslContextFactory.getExcludeCipherSuites();
158 }
159
160 /* ------------------------------------------------------------ */
161 /**
162 * @see org.eclipse.jetty.server.ssl.SslConnector#getIncludeCipherSuites()
163 * @deprecated
164 */
165 @Deprecated
166 public String[] getIncludeCipherSuites()
167 {
168 return _sslContextFactory.getIncludeCipherSuites();
169 }
170
171 /* ------------------------------------------------------------ */
172 /**
173 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystore()
174 * @deprecated
175 */
176 @Deprecated
177 public String getKeystore()
178 {
179 return _sslContextFactory.getKeyStorePath();
180 }
181
182 /* ------------------------------------------------------------ */
183 /**
184 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystoreType()
185 * @deprecated
186 */
187 @Deprecated
188 public String getKeystoreType()
189 {
190 return _sslContextFactory.getKeyStoreType();
191 }
192
193 /* ------------------------------------------------------------ */
194 /**
195 * @see org.eclipse.jetty.server.ssl.SslConnector#getNeedClientAuth()
196 * @deprecated
197 */
198 @Deprecated
199 public boolean getNeedClientAuth()
200 {
201 return _sslContextFactory.getNeedClientAuth();
202 }
203
204 /* ------------------------------------------------------------ */
205 /**
206 * @see org.eclipse.jetty.server.ssl.SslConnector#getProtocol()
207 * @deprecated
208 */
209 @Deprecated
210 public String getProtocol()
211 {
212 return _sslContextFactory.getProtocol();
213 }
214
215 /* ------------------------------------------------------------ */
216 /**
217 * @see org.eclipse.jetty.server.ssl.SslConnector#getProvider()
218 * @deprecated
219 */
220 @Deprecated
221 public String getProvider() {
222 return _sslContextFactory.getProvider();
223 }
224
225 /* ------------------------------------------------------------ */
226 /**
227 * @see org.eclipse.jetty.server.ssl.SslConnector#getSecureRandomAlgorithm()
228 * @deprecated
229 */
230 @Deprecated
231 public String getSecureRandomAlgorithm()
232 {
233 return _sslContextFactory.getSecureRandomAlgorithm();
234 }
235
236 /* ------------------------------------------------------------ */
237 /**
238 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslKeyManagerFactoryAlgorithm()
239 * @deprecated
240 */
241 @Deprecated
242 public String getSslKeyManagerFactoryAlgorithm()
243 {
244 return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
245 }
246
247 /* ------------------------------------------------------------ */
248 /**
249 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslTrustManagerFactoryAlgorithm()
250 * @deprecated
251 */
252 @Deprecated
253 public String getSslTrustManagerFactoryAlgorithm()
254 {
255 return _sslContextFactory.getTrustManagerFactoryAlgorithm();
256 }
257
258 /* ------------------------------------------------------------ */
259 /**
260 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststore()
261 * @deprecated
262 */
263 @Deprecated
264 public String getTruststore()
265 {
266 return _sslContextFactory.getTrustStore();
267 }
268
269 /* ------------------------------------------------------------ */
270 /**
271 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslContextFactory()
272 */
273 // @Override
274 public SslContextFactory getSslContextFactory()
275 {
276 return _sslContextFactory;
277 }
278
279 /* ------------------------------------------------------------ */
280 /**
281 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststoreType()
282 * @deprecated
283 */
284 @Deprecated
285 public String getTruststoreType()
286 {
287 return _sslContextFactory.getTrustStoreType();
288 }
289
290 /* ------------------------------------------------------------ */
291 /**
292 * @see org.eclipse.jetty.server.ssl.SslConnector#getWantClientAuth()
293 * @deprecated
294 */
295 @Deprecated
296 public boolean getWantClientAuth()
297 {
298 return _sslContextFactory.getWantClientAuth();
299 }
300
301 /* ------------------------------------------------------------ */
302 /**
303 * By default, we're confidential, given we speak SSL. But, if we've been told about an
304 * confidential port, and said port is not our port, then we're not. This allows separation of
305 * listeners providing INTEGRAL versus CONFIDENTIAL constraints, such as one SSL listener
306 * configured to require client certs providing CONFIDENTIAL, whereas another SSL listener not
307 * requiring client certs providing mere INTEGRAL constraints.
308 */
309 @Override
310 public boolean isConfidential(Request request)
311 {
312 final int confidentialPort = getConfidentialPort();
313 return confidentialPort == 0 || confidentialPort == request.getServerPort();
314 }
315
316 /* ------------------------------------------------------------ */
317 /**
318 * By default, we're integral, given we speak SSL. But, if we've been told about an integral
319 * port, and said port is not our port, then we're not. This allows separation of listeners
320 * providing INTEGRAL versus CONFIDENTIAL constraints, such as one SSL listener configured to
321 * require client certs providing CONFIDENTIAL, whereas another SSL listener not requiring
322 * client certs providing mere INTEGRAL constraints.
323 */
324 @Override
325 public boolean isIntegral(Request request)
326 {
327 final int integralPort = getIntegralPort();
328 return integralPort == 0 || integralPort == request.getServerPort();
329 }
330
331 /* ------------------------------------------------------------ */
332 @Override
333 public void open() throws IOException
334 {
335 _sslContextFactory.checkKeyStore();
336 try
337 {
338 _sslContextFactory.start();
339 }
340 catch(Exception e)
341 {
342 throw new RuntimeIOException(e);
343 }
344 super.open();
345 }
346
347 /* ------------------------------------------------------------ */
348 /**
349 * {@inheritDoc}
350 */
351 @Override
352 protected void doStart() throws Exception
353 {
354 _sslContextFactory.checkKeyStore();
355 _sslContextFactory.start();
356
357 super.doStart();
358 }
359
360 /* ------------------------------------------------------------ */
361 /**
362 * @see org.eclipse.jetty.server.bio.SocketConnector#doStop()
363 */
364 @Override
365 protected void doStop() throws Exception
366 {
367 _sslContextFactory.stop();
368
369 super.doStop();
370 }
371
372 /* ------------------------------------------------------------ */
373 /**
374 * @param host The host name that this server should listen on
375 * @param port the port that this server should listen on
376 * @param backlog See {@link ServerSocket#bind(java.net.SocketAddress, int)}
377 * @return A new {@link ServerSocket socket object} bound to the supplied address with all other
378 * settings as per the current configuration of this connector.
379 * @see #setWantClientAuth(boolean)
380 * @see #setNeedClientAuth(boolean)
381 * @exception IOException
382 */
383 @Override
384 protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
385 {
386 return _sslContextFactory.newSslServerSocket(host,port,backlog);
387 }
388
389 /* ------------------------------------------------------------ */
390 /**
391 * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
392 * @deprecated
393 */
394 @Deprecated
395 public void setExcludeCipherSuites(String[] cipherSuites)
396 {
397 _sslContextFactory.setExcludeCipherSuites(cipherSuites);
398 }
399
400 /* ------------------------------------------------------------ */
401 /**
402 * @see org.eclipse.jetty.server.ssl.SslConnector#setIncludeCipherSuites(java.lang.String[])
403 * @deprecated
404 */
405 @Deprecated
406 public void setIncludeCipherSuites(String[] cipherSuites)
407 {
408 _sslContextFactory.setIncludeCipherSuites(cipherSuites);
409 }
410
411 /* ------------------------------------------------------------ */
412 /**
413 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeyPassword(java.lang.String)
414 * @deprecated
415 */
416 @Deprecated
417 public void setKeyPassword(String password)
418 {
419 _sslContextFactory.setKeyManagerPassword(password);
420 }
421
422 /* ------------------------------------------------------------ */
423 /**
424 * @param keystore The resource path to the keystore, or null for built in keystores.
425 * @deprecated
426 */
427 @Deprecated
428 public void setKeystore(String keystore)
429 {
430 _sslContextFactory.setKeyStorePath(keystore);
431 }
432
433 /* ------------------------------------------------------------ */
434 /**
435 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystoreType(java.lang.String)
436 * @deprecated
437 */
438 @Deprecated
439 public void setKeystoreType(String keystoreType)
440 {
441 _sslContextFactory.setKeyStoreType(keystoreType);
442 }
443
444 /* ------------------------------------------------------------ */
445 /**
446 * Set the value of the needClientAuth property
447 *
448 * @param needClientAuth true iff we require client certificate authentication.
449 * @deprecated
450 */
451 @Deprecated
452 public void setNeedClientAuth(boolean needClientAuth)
453 {
454 _sslContextFactory.setNeedClientAuth(needClientAuth);
455 }
456
457 /* ------------------------------------------------------------ */
458 /**
459 * @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String)
460 * @deprecated
461 */
462 @Deprecated
463 public void setPassword(String password)
464 {
465 _sslContextFactory.setKeyStorePassword(password);
466 }
467
468 /* ------------------------------------------------------------ */
469 /**
470 * @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String)
471 * @deprecated
472 */
473 @Deprecated
474 public void setTrustPassword(String password)
475 {
476 _sslContextFactory.setTrustStorePassword(password);
477 }
478
479 /* ------------------------------------------------------------ */
480 /**
481 * @see org.eclipse.jetty.server.ssl.SslConnector#setProtocol(java.lang.String)
482 * @deprecated
483 */
484 @Deprecated
485 public void setProtocol(String protocol)
486 {
487 _sslContextFactory.setProtocol(protocol);
488 }
489
490 /* ------------------------------------------------------------ */
491 /**
492 * @see org.eclipse.jetty.server.ssl.SslConnector#setProvider(java.lang.String)
493 * @deprecated
494 */
495 @Deprecated
496 public void setProvider(String provider) {
497 _sslContextFactory.setProvider(provider);
498 }
499
500 /* ------------------------------------------------------------ */
501 /**
502 * @see org.eclipse.jetty.server.ssl.SslConnector#setSecureRandomAlgorithm(java.lang.String)
503 * @deprecated
504 */
505 @Deprecated
506 public void setSecureRandomAlgorithm(String algorithm)
507 {
508 _sslContextFactory.setSecureRandomAlgorithm(algorithm);
509 }
510
511 /* ------------------------------------------------------------ */
512 /**
513 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslKeyManagerFactoryAlgorithm(java.lang.String)
514 * @deprecated
515 */
516 @Deprecated
517 public void setSslKeyManagerFactoryAlgorithm(String algorithm)
518 {
519 _sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
520 }
521
522 /* ------------------------------------------------------------ */
523 /**
524 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String)
525 * @deprecated
526 */
527 @Deprecated
528 public void setSslTrustManagerFactoryAlgorithm(String algorithm)
529 {
530 _sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
531 }
532
533 /* ------------------------------------------------------------ */
534 /**
535 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststore(java.lang.String)
536 * @deprecated
537 */
538 @Deprecated
539 public void setTruststore(String truststore)
540 {
541 _sslContextFactory.setTrustStore(truststore);
542 }
543
544 /* ------------------------------------------------------------ */
545 /**
546 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String)
547 * @deprecated
548 */
549 @Deprecated
550 public void setTruststoreType(String truststoreType)
551 {
552 _sslContextFactory.setTrustStoreType(truststoreType);
553 }
554
555 /* ------------------------------------------------------------ */
556 /**
557 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
558 * @deprecated
559 */
560 @Deprecated
561 public void setSslContext(SSLContext sslContext)
562 {
563 _sslContextFactory.setSslContext(sslContext);
564 }
565
566 /* ------------------------------------------------------------ */
567 /**
568 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
569 * @deprecated
570 */
571 @Deprecated
572 public SSLContext getSslContext()
573 {
574 return _sslContextFactory.getSslContext();
575 }
576
577 /* ------------------------------------------------------------ */
578 /**
579 * Set the value of the _wantClientAuth property. This property is used
580 * internally when opening server sockets.
581 *
582 * @param wantClientAuth true if we want client certificate authentication.
583 * @see SSLServerSocket#setWantClientAuth
584 * @deprecated
585 */
586 @Deprecated
587 public void setWantClientAuth(boolean wantClientAuth)
588 {
589 _sslContextFactory.setWantClientAuth(wantClientAuth);
590 }
591
592 /* ------------------------------------------------------------ */
593 /**
594 * Set the time in milliseconds for so_timeout during ssl handshaking
595 * @param msec a non-zero value will be used to set so_timeout during
596 * ssl handshakes. A zero value means the maxIdleTime is used instead.
597 */
598 public void setHandshakeTimeout (int msec)
599 {
600 _handshakeTimeout = msec;
601 }
602
603
604 /* ------------------------------------------------------------ */
605 public int getHandshakeTimeout ()
606 {
607 return _handshakeTimeout;
608 }
609
610 /* ------------------------------------------------------------ */
611 public class SslConnectorEndPoint extends ConnectorEndPoint
612 {
613 public SslConnectorEndPoint(Socket socket) throws IOException
614 {
615 super(socket);
616 }
617
618 @Override
619 public void shutdownOutput() throws IOException
620 {
621 close();
622 }
623
624 @Override
625 public void shutdownInput() throws IOException
626 {
627 close();
628 }
629
630 @Override
631 public void run()
632 {
633 try
634 {
635 int handshakeTimeout = getHandshakeTimeout();
636 int oldTimeout = _socket.getSoTimeout();
637 if (handshakeTimeout > 0)
638 _socket.setSoTimeout(handshakeTimeout);
639
640 final SSLSocket ssl=(SSLSocket)_socket;
641 ssl.addHandshakeCompletedListener(new HandshakeCompletedListener()
642 {
643 boolean handshook=false;
644 public void handshakeCompleted(HandshakeCompletedEvent event)
645 {
646 if (handshook)
647 {
648 if (!_sslContextFactory.isAllowRenegotiate())
649 {
650 LOG.warn("SSL renegotiate denied: "+ssl);
651 try{ssl.close();}catch(IOException e){LOG.warn(e);}
652 }
653 }
654 else
655 handshook=true;
656 }
657 });
658 ssl.startHandshake();
659
660 if (handshakeTimeout>0)
661 _socket.setSoTimeout(oldTimeout);
662
663 super.run();
664 }
665 catch (SSLException e)
666 {
667 LOG.debug(e);
668 try{close();}
669 catch(IOException e2){LOG.ignore(e2);}
670 }
671 catch (IOException e)
672 {
673 LOG.debug(e);
674 try{close();}
675 catch(IOException e2){LOG.ignore(e2);}
676 }
677 }
678 }
679
680 /* ------------------------------------------------------------ */
681 /**
682 * Unsupported.
683 *
684 * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
685 * @deprecated
686 */
687 @Deprecated
688 public String getAlgorithm()
689 {
690 throw new UnsupportedOperationException();
691 }
692
693 /* ------------------------------------------------------------ */
694 /**
695 * Unsupported.
696 *
697 * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
698 * @deprecated
699 */
700 @Deprecated
701 public void setAlgorithm(String algorithm)
702 {
703 throw new UnsupportedOperationException();
704 }
705 }