View Javadoc

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 }