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