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