View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-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.nio.channels.SelectionKey;
18  import java.nio.channels.SocketChannel;
19  import javax.net.ssl.SSLContext;
20  import javax.net.ssl.SSLEngine;
21  import javax.net.ssl.SSLSession;
22  import javax.net.ssl.SSLSocket;
23  
24  import org.eclipse.jetty.http.HttpParser;
25  import org.eclipse.jetty.http.HttpSchemes;
26  import org.eclipse.jetty.http.ssl.SslContextFactory;
27  import org.eclipse.jetty.io.Buffers;
28  import org.eclipse.jetty.io.Buffers.Type;
29  import org.eclipse.jetty.io.BuffersFactory;
30  import org.eclipse.jetty.io.Connection;
31  import org.eclipse.jetty.io.EndPoint;
32  import org.eclipse.jetty.io.bio.SocketEndPoint;
33  import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
34  import org.eclipse.jetty.io.nio.SelectorManager.SelectSet;
35  import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
36  import org.eclipse.jetty.server.HttpConnection;
37  import org.eclipse.jetty.server.Request;
38  import org.eclipse.jetty.server.nio.SelectChannelConnector;
39  import org.eclipse.jetty.util.log.Log;
40  
41  /* ------------------------------------------------------------ */
42  /**
43   * SslSelectChannelConnector.
44   *
45   * @org.apache.xbean.XBean element="sslConnector" description="Creates an NIO ssl connector"
46   */
47  public class SslSelectChannelConnector extends SelectChannelConnector implements SslConnector
48  {
49      private final SslContextFactory _sslContextFactory;
50      private Buffers _sslBuffers;
51  
52      /* ------------------------------------------------------------ */
53      public SslSelectChannelConnector()
54      {
55          this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
56      }
57  
58      /* ------------------------------------------------------------ */
59      public SslSelectChannelConnector(SslContextFactory sslContextFactory)
60      {
61          _sslContextFactory = sslContextFactory;
62          setUseDirectBuffers(false);
63      }
64  
65      /* ------------------------------------------------------------ */
66      /**
67       * Allow the Listener a chance to customise the request. before the server
68       * does its stuff. <br>
69       * This allows the required attributes to be set for SSL requests. <br>
70       * The requirements of the Servlet specs are:
71       * <ul>
72       * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
73       * String (since Servlet Spec 3.0).</li>
74       * <li> an attribute named "javax.servlet.request.cipher_suite" of type
75       * String.</li>
76       * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
77       * <li> an attribute named "javax.servlet.request.X509Certificate" of type
78       * java.security.cert.X509Certificate[]. This is an array of objects of type
79       * X509Certificate, the order of this array is defined as being in ascending
80       * order of trust. The first certificate in the chain is the one set by the
81       * client, the next is the one used to authenticate the first, and so on.
82       * </li>
83       * </ul>
84       *
85       * @param endpoint
86       *                The Socket the request arrived on. This should be a
87       *                {@link SocketEndPoint} wrapping a {@link SSLSocket}.
88       * @param request
89       *                HttpRequest to be customised.
90       */
91      @Override
92      public void customize(EndPoint endpoint, Request request) throws IOException
93      {
94          request.setScheme(HttpSchemes.HTTPS);
95          super.customize(endpoint,request);
96  
97          SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint;
98          SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine();
99          SSLSession sslSession=sslEngine.getSession();
100 
101         SslCertificates.customize(sslSession,endpoint,request);
102     }
103 
104     /* ------------------------------------------------------------ */
105     /**
106      * @return True if SSL re-negotiation is allowed (default false)
107      * @deprecated
108      */
109     @Deprecated
110     public boolean isAllowRenegotiate()
111     {
112         return _sslContextFactory.isAllowRenegotiate();
113     }
114 
115     /* ------------------------------------------------------------ */
116     /**
117      * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
118      * a vulnerability in SSL/TLS with re-negotiation.  If your JVM
119      * does not have CVE-2009-3555 fixed, then re-negotiation should
120      * not be allowed.  CVE-2009-3555 was fixed in Sun java 1.6 with a ban
121      * of renegotiate in u19 and with RFC5746 in u22.
122      * @param allowRenegotiate true if re-negotiation is allowed (default false)
123      * @deprecated
124      */
125     @Deprecated
126     public void setAllowRenegotiate(boolean allowRenegotiate)
127     {
128         _sslContextFactory.setAllowRenegotiate(allowRenegotiate);
129     }
130 
131     /* ------------------------------------------------------------ */
132     /**
133      * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
134      * @deprecated
135      */
136     @Deprecated
137     public String[] getExcludeCipherSuites()
138     {
139         return _sslContextFactory.getExcludeCipherSuites();
140     }
141 
142     /* ------------------------------------------------------------ */
143     /**
144      * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
145      * @deprecated
146      */
147     @Deprecated
148     public void setExcludeCipherSuites(String[] cipherSuites)
149     {
150         _sslContextFactory.setExcludeCipherSuites(cipherSuites);
151     }
152 
153     /* ------------------------------------------------------------ */
154     /**
155      * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
156      * @deprecated
157      */
158     @Deprecated
159     public String[] getIncludeCipherSuites()
160     {
161         return _sslContextFactory.getIncludeCipherSuites();
162     }
163 
164     /* ------------------------------------------------------------ */
165     /**
166      * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
167      * @deprecated
168      */
169     @Deprecated
170     public void setIncludeCipherSuites(String[] cipherSuites)
171     {
172         _sslContextFactory.setIncludeCipherSuites(cipherSuites);
173     }
174 
175     /* ------------------------------------------------------------ */
176     /**
177      * @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String)
178      * @deprecated
179      */
180     @Deprecated
181     public void setPassword(String password)
182     {
183         _sslContextFactory.setKeyStorePassword(password);
184     }
185 
186     /* ------------------------------------------------------------ */
187     /**
188      * @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String)
189      * @deprecated
190      */
191     @Deprecated
192     public void setTrustPassword(String password)
193     {
194         _sslContextFactory.setTrustStorePassword(password);
195     }
196 
197     /* ------------------------------------------------------------ */
198     /**
199      * @see org.eclipse.jetty.server.ssl.SslConnector#setKeyPassword(java.lang.String)
200      * @deprecated
201      */
202     @Deprecated
203     public void setKeyPassword(String password)
204     {
205         _sslContextFactory.setKeyManagerPassword(password);
206     }
207 
208     /* ------------------------------------------------------------ */
209     /**
210      * Unsupported.
211      *
212      * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
213      * @deprecated
214      */
215     @Deprecated
216     public String getAlgorithm()
217     {
218         throw new UnsupportedOperationException();
219     }
220 
221     /* ------------------------------------------------------------ */
222     /**
223      * Unsupported.
224      *
225      * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
226      * @deprecated
227      */
228     @Deprecated
229     public void setAlgorithm(String algorithm)
230     {
231         throw new UnsupportedOperationException();
232     }
233 
234     /* ------------------------------------------------------------ */
235     /**
236      * @see org.eclipse.jetty.server.ssl.SslConnector#getProtocol()
237      * @deprecated
238      */
239     @Deprecated
240     public String getProtocol()
241     {
242         return _sslContextFactory.getProtocol();
243     }
244 
245     /* ------------------------------------------------------------ */
246     /**
247      * @see org.eclipse.jetty.server.ssl.SslConnector#setProtocol(java.lang.String)
248      * @deprecated
249      */
250     @Deprecated
251     public void setProtocol(String protocol)
252     {
253         _sslContextFactory.setProtocol(protocol);
254     }
255 
256     /* ------------------------------------------------------------ */
257     /**
258      * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystore(java.lang.String)
259      * @deprecated
260      */
261     @Deprecated
262     public void setKeystore(String keystore)
263     {
264         _sslContextFactory.setKeyStore(keystore);
265     }
266 
267     /* ------------------------------------------------------------ */
268     /**
269      * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystore()
270      * @deprecated
271      */
272     @Deprecated
273     public String getKeystore()
274     {
275         return _sslContextFactory.getKeyStore();
276     }
277 
278     /* ------------------------------------------------------------ */
279     /**
280      * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystoreType()
281      * @deprecated
282      */
283     @Deprecated
284     public String getKeystoreType()
285     {
286         return _sslContextFactory.getKeyStoreType();
287     }
288 
289     /* ------------------------------------------------------------ */
290     /**
291      * @see org.eclipse.jetty.server.ssl.SslConnector#getNeedClientAuth()
292      * @deprecated
293      */
294     @Deprecated
295     public boolean getNeedClientAuth()
296     {
297         return _sslContextFactory.getNeedClientAuth();
298     }
299 
300     /* ------------------------------------------------------------ */
301     /**
302      * @see org.eclipse.jetty.server.ssl.SslConnector#getWantClientAuth()
303      * @deprecated
304      */
305     @Deprecated
306     public boolean getWantClientAuth()
307     {
308         return _sslContextFactory.getWantClientAuth();
309     }
310 
311     /* ------------------------------------------------------------ */
312     /**
313      * @see org.eclipse.jetty.server.ssl.SslConnector#setNeedClientAuth(boolean)
314      * @deprecated
315      */
316     @Deprecated
317     public void setNeedClientAuth(boolean needClientAuth)
318     {
319         _sslContextFactory.setNeedClientAuth(needClientAuth);
320     }
321 
322     /* ------------------------------------------------------------ */
323     /**
324      * @see org.eclipse.jetty.server.ssl.SslConnector#setWantClientAuth(boolean)
325      * @deprecated
326      */
327     @Deprecated
328     public void setWantClientAuth(boolean wantClientAuth)
329     {
330         _sslContextFactory.setWantClientAuth(wantClientAuth);
331     }
332 
333     /* ------------------------------------------------------------ */
334     /**
335      * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystoreType(java.lang.String)
336      * @deprecated
337      */
338     @Deprecated
339     public void setKeystoreType(String keystoreType)
340     {
341         _sslContextFactory.setKeyStoreType(keystoreType);
342     }
343 
344     /* ------------------------------------------------------------ */
345     /**
346      * @see org.eclipse.jetty.server.ssl.SslConnector#getProvider()
347      * @deprecated
348      */
349     @Deprecated
350     public String getProvider()
351     {
352         return _sslContextFactory.getProvider();
353     }
354 
355     /* ------------------------------------------------------------ */
356     /**
357      * @see org.eclipse.jetty.server.ssl.SslConnector#getSecureRandomAlgorithm()
358      * @deprecated
359      */
360     @Deprecated
361     public String getSecureRandomAlgorithm()
362     {
363         return _sslContextFactory.getSecureRandomAlgorithm();
364     }
365 
366     /* ------------------------------------------------------------ */
367     /**
368      * @see org.eclipse.jetty.server.ssl.SslConnector#getSslKeyManagerFactoryAlgorithm()
369      * @deprecated
370      */
371     @Deprecated
372     public String getSslKeyManagerFactoryAlgorithm()
373     {
374         return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
375     }
376 
377     /* ------------------------------------------------------------ */
378     /**
379      * @see org.eclipse.jetty.server.ssl.SslConnector#getSslTrustManagerFactoryAlgorithm()
380      * @deprecated
381      */
382     @Deprecated
383     public String getSslTrustManagerFactoryAlgorithm()
384     {
385         return _sslContextFactory.getTrustManagerFactoryAlgorithm();
386     }
387 
388     /* ------------------------------------------------------------ */
389     /**
390      * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststore()
391      * @deprecated
392      */
393     @Deprecated
394     public String getTruststore()
395     {
396         return _sslContextFactory.getTrustStore();
397     }
398 
399     /* ------------------------------------------------------------ */
400     /**
401      * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststoreType()
402      * @deprecated
403      */
404     @Deprecated
405     public String getTruststoreType()
406     {
407         return _sslContextFactory.getTrustStoreType();
408     }
409 
410     /* ------------------------------------------------------------ */
411     /**
412      * @see org.eclipse.jetty.server.ssl.SslConnector#setProvider(java.lang.String)
413      * @deprecated
414      */
415     @Deprecated
416     public void setProvider(String provider)
417     {
418         _sslContextFactory.setProvider(provider);
419     }
420 
421     /* ------------------------------------------------------------ */
422     /**
423      * @see org.eclipse.jetty.server.ssl.SslConnector#setSecureRandomAlgorithm(java.lang.String)
424      * @deprecated
425      */
426     @Deprecated
427     public void setSecureRandomAlgorithm(String algorithm)
428     {
429         _sslContextFactory.setSecureRandomAlgorithm(algorithm);
430     }
431 
432     /* ------------------------------------------------------------ */
433     /**
434      * @see org.eclipse.jetty.server.ssl.SslConnector#setSslKeyManagerFactoryAlgorithm(java.lang.String)
435      * @deprecated
436      */
437     @Deprecated
438     public void setSslKeyManagerFactoryAlgorithm(String algorithm)
439     {
440         _sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
441     }
442 
443     /* ------------------------------------------------------------ */
444     /**
445      * @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String)
446      * @deprecated
447      */
448     @Deprecated
449     public void setSslTrustManagerFactoryAlgorithm(String algorithm)
450     {
451         _sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
452     }
453 
454     /* ------------------------------------------------------------ */
455     /**
456      * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststore(java.lang.String)
457      * @deprecated
458      */
459     @Deprecated
460     public void setTruststore(String truststore)
461     {
462         _sslContextFactory.setTrustStore(truststore);
463     }
464 
465     /* ------------------------------------------------------------ */
466     /**
467      * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String)
468      * @deprecated
469      */
470     @Deprecated
471     public void setTruststoreType(String truststoreType)
472     {
473         _sslContextFactory.setTrustStoreType(truststoreType);
474     }
475 
476     /* ------------------------------------------------------------ */
477     /**
478      * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
479      * @deprecated
480      */
481     @Deprecated
482     public void setSslContext(SSLContext sslContext)
483     {
484         _sslContextFactory.setSslContext(sslContext);
485     }
486 
487     /* ------------------------------------------------------------ */
488     /**
489      * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
490      * @deprecated
491      */
492     @Deprecated
493     public SSLContext getSslContext()
494     {
495         return _sslContextFactory.getSslContext();
496     }
497 
498     /* ------------------------------------------------------------ */
499     /**
500      * @see org.eclipse.jetty.server.ssl.SslConnector#getSslContextFactory()
501      */
502     public SslContextFactory getSslContextFactory()
503     {
504         return _sslContextFactory;
505     }
506 
507     /* ------------------------------------------------------------ */
508     /**
509      * By default, we're confidential, given we speak SSL. But, if we've been
510      * told about an confidential port, and said port is not our port, then
511      * we're not. This allows separation of listeners providing INTEGRAL versus
512      * CONFIDENTIAL constraints, such as one SSL listener configured to require
513      * client certs providing CONFIDENTIAL, whereas another SSL listener not
514      * requiring client certs providing mere INTEGRAL constraints.
515      */
516     @Override
517     public boolean isConfidential(Request request)
518     {
519         final int confidentialPort=getConfidentialPort();
520         return confidentialPort==0||confidentialPort==request.getServerPort();
521     }
522 
523     /* ------------------------------------------------------------ */
524     /**
525      * By default, we're integral, given we speak SSL. But, if we've been told
526      * about an integral port, and said port is not our port, then we're not.
527      * This allows separation of listeners providing INTEGRAL versus
528      * CONFIDENTIAL constraints, such as one SSL listener configured to require
529      * client certs providing CONFIDENTIAL, whereas another SSL listener not
530      * requiring client certs providing mere INTEGRAL constraints.
531      */
532     @Override
533     public boolean isIntegral(Request request)
534     {
535         final int integralPort=getIntegralPort();
536         return integralPort==0||integralPort==request.getServerPort();
537     }
538 
539     /* ------------------------------------------------------------------------------- */
540     @Override
541     protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
542     {
543         SSLEngine engine = createSSLEngine(channel);
544         SslSelectChannelEndPoint endp = new SslSelectChannelEndPoint(_sslBuffers,channel,selectSet,key,engine, SslSelectChannelConnector.this._maxIdleTime);
545         endp.setAllowRenegotiate(_sslContextFactory.isAllowRenegotiate());
546         return endp;
547     }
548 
549     /* ------------------------------------------------------------------------------- */
550     @Override
551     protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
552     {
553         HttpConnection connection=(HttpConnection)super.newConnection(channel,endpoint);
554         ((HttpParser)connection.getParser()).setForceContentBuffer(true);
555         return connection;
556     }
557 
558     /* ------------------------------------------------------------ */
559     /**
560      * @param channel A channel which if passed is used as to extract remote
561      * host and port for the purposes of SSL session caching
562      * @return A SSLEngine for a new or cached SSL Session
563      * @throws IOException if the SSLEngine cannot be created
564      */
565     protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException
566     {
567         SSLEngine engine;
568         if (channel != null && _sslContextFactory.isSessionCachingEnabled())
569         {
570             String peerHost = channel.socket().getInetAddress().getHostAddress();
571             int peerPort = channel.socket().getPort();
572             engine = _sslContextFactory.getSslContext().createSSLEngine(peerHost, peerPort);
573         }
574         else
575         {
576             engine = _sslContextFactory.getSslContext().createSSLEngine();
577         }
578         customizeEngine(engine);
579         return engine;
580     }
581 
582     /* ------------------------------------------------------------ */
583     private void customizeEngine(SSLEngine engine)
584     {
585         engine.setUseClientMode(false);
586 
587         if (_sslContextFactory.getWantClientAuth())
588             engine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
589         if (_sslContextFactory.getNeedClientAuth())
590             engine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
591 
592         engine.setEnabledCipherSuites(
593                 _sslContextFactory.selectCipherSuites(engine.getEnabledCipherSuites(),
594                                                       engine.getSupportedCipherSuites()));
595     }
596 
597     /* ------------------------------------------------------------ */
598     /**
599      * @see org.eclipse.jetty.server.nio.SelectChannelConnector#doStart()
600      */
601     @Override
602     protected void doStart() throws Exception
603     {
604         if (!_sslContextFactory.checkConfig())
605         {
606             throw new IllegalStateException("SSL context is not configured correctly.");
607         }
608 
609         _sslContextFactory.start();
610 
611         SSLEngine sslEngine = _sslContextFactory.getSslContext().createSSLEngine();
612 
613         sslEngine.setUseClientMode(false);
614         sslEngine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
615         sslEngine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
616 
617         sslEngine.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
618                                             sslEngine.getEnabledCipherSuites(),
619                                             sslEngine.getSupportedCipherSuites()));
620 
621         SSLSession sslSession = sslEngine.getSession();
622 
623         _sslBuffers = BuffersFactory.newBuffers(
624                 getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,sslSession.getApplicationBufferSize(),
625                 getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,sslSession.getApplicationBufferSize(),
626                 getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,getMaxBuffers()
627         );
628 
629         if (getRequestHeaderSize()<sslSession.getApplicationBufferSize())
630             setRequestHeaderSize(sslSession.getApplicationBufferSize());
631         if (getRequestBufferSize()<sslSession.getApplicationBufferSize())
632             setRequestBufferSize(sslSession.getApplicationBufferSize());
633 
634         super.doStart();
635     }
636 
637     /* ------------------------------------------------------------ */
638     /**
639      * @see org.eclipse.jetty.server.nio.SelectChannelConnector#doStop()
640      */
641     @Override
642     protected void doStop() throws Exception
643     {
644         _sslContextFactory.stop();
645         _sslBuffers=null;
646         super.doStop();
647     }
648 
649     /* ------------------------------------------------------------ */
650     /**
651      * @return SSL buffers
652      */
653     public Buffers getSslBuffers()
654     {
655         return _sslBuffers;
656     }
657 }