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