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