View Javadoc

1   package org.eclipse.jetty.server.ssl;
2   //========================================================================
3   //Copyright 2011-2012 Mort Bay Consulting Pty. Ltd.
4   //------------------------------------------------------------------------
5   //All rights reserved. This program and the accompanying materials
6   //are made available under the terms of the Eclipse Public License v1.0
7   //and Apache License v2.0 which accompanies this distribution.
8   //The Eclipse Public License is available at
9   //http://www.eclipse.org/legal/epl-v10.html
10  //The Apache License v2.0 is available at
11  //http://www.opensource.org/licenses/apache2.0.php
12  //You may elect to redistribute this code under either of these licenses.
13  //========================================================================
14  
15  import java.io.ByteArrayInputStream;
16  import java.io.IOException;
17  import java.security.cert.X509Certificate;
18  
19  import javax.net.ssl.SSLPeerUnverifiedException;
20  import javax.net.ssl.SSLSession;
21  import javax.net.ssl.SSLSocket;
22  
23  import org.eclipse.jetty.http.HttpSchemes;
24  import org.eclipse.jetty.io.EndPoint;
25  import org.eclipse.jetty.io.bio.SocketEndPoint;
26  import org.eclipse.jetty.server.Request;
27  import org.eclipse.jetty.util.TypeUtil;
28  import org.eclipse.jetty.util.log.Log;
29  import org.eclipse.jetty.util.log.Logger;
30  
31  public class SslCertificates
32  {
33      private static final Logger LOG = Log.getLogger(SslCertificates.class);
34  
35      /**
36       * The name of the SSLSession attribute that will contain any cached information.
37       */
38      static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
39  
40      public static X509Certificate[] getCertChain(SSLSession sslSession)
41      {
42          try
43          {
44              javax.security.cert.X509Certificate javaxCerts[]=sslSession.getPeerCertificateChain();
45              if (javaxCerts==null||javaxCerts.length==0)
46                  return null;
47  
48              int length=javaxCerts.length;
49              X509Certificate[] javaCerts=new X509Certificate[length];
50  
51              java.security.cert.CertificateFactory cf=java.security.cert.CertificateFactory.getInstance("X.509");
52              for (int i=0; i<length; i++)
53              {
54                  byte bytes[]=javaxCerts[i].getEncoded();
55                  ByteArrayInputStream stream=new ByteArrayInputStream(bytes);
56                  javaCerts[i]=(X509Certificate)cf.generateCertificate(stream);
57              }
58  
59              return javaCerts;
60          }
61          catch (SSLPeerUnverifiedException pue)
62          {
63              return null;
64          }
65          catch (Exception e)
66          {
67              LOG.warn(Log.EXCEPTION,e);
68              return null;
69          }
70      }
71      
72  
73      /* ------------------------------------------------------------ */
74      /**
75       * Allow the Listener a chance to customise the request. before the server
76       * does its stuff. <br>
77       * This allows the required attributes to be set for SSL requests. <br>
78       * The requirements of the Servlet specs are:
79       * <ul>
80       * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
81       * String (since Servlet Spec 3.0).</li>
82       * <li> an attribute named "javax.servlet.request.cipher_suite" of type
83       * String.</li>
84       * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
85       * <li> an attribute named "javax.servlet.request.X509Certificate" of type
86       * java.security.cert.X509Certificate[]. This is an array of objects of type
87       * X509Certificate, the order of this array is defined as being in ascending
88       * order of trust. The first certificate in the chain is the one set by the
89       * client, the next is the one used to authenticate the first, and so on.
90       * </li>
91       * </ul>
92       * 
93       * @param endpoint
94       *                The Socket the request arrived on. This should be a
95       *                {@link SocketEndPoint} wrapping a {@link SSLSocket}.
96       * @param request
97       *                HttpRequest to be customised.
98       */
99      public static void customize(SSLSession sslSession, EndPoint endpoint, Request request) throws IOException
100     {
101         request.setScheme(HttpSchemes.HTTPS);
102 
103         try
104         {
105             String cipherSuite=sslSession.getCipherSuite();
106             Integer keySize;
107             X509Certificate[] certs;
108             String idStr;
109 
110             CachedInfo cachedInfo=(CachedInfo)sslSession.getValue(CACHED_INFO_ATTR);
111             if (cachedInfo!=null)
112             {
113                 keySize=cachedInfo.getKeySize();
114                 certs=cachedInfo.getCerts();
115                 idStr=cachedInfo.getIdStr();
116             }
117             else
118             {
119                 keySize=new Integer(ServletSSL.deduceKeyLength(cipherSuite));
120                 certs=SslCertificates.getCertChain(sslSession);
121                 byte[] bytes = sslSession.getId();
122                 idStr = TypeUtil.toHexString(bytes);
123                 cachedInfo=new CachedInfo(keySize,certs,idStr);
124                 sslSession.putValue(CACHED_INFO_ATTR,cachedInfo);
125             }
126 
127             if (certs!=null)
128                 request.setAttribute("javax.servlet.request.X509Certificate",certs);
129 
130             request.setAttribute("javax.servlet.request.cipher_suite",cipherSuite);
131             request.setAttribute("javax.servlet.request.key_size",keySize);
132             request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
133         }
134         catch (Exception e)
135         {
136             LOG.warn(Log.EXCEPTION,e);
137         }
138     }
139 
140     /* ------------------------------------------------------------ */
141     /* ------------------------------------------------------------ */
142     /* ------------------------------------------------------------ */
143     /**
144      * Simple bundle of information that is cached in the SSLSession. Stores the
145      * effective keySize and the client certificate chain.
146      */
147     private static class CachedInfo
148     {
149         private final X509Certificate[] _certs;
150         private final Integer _keySize;
151         private final String _idStr;
152 
153         CachedInfo(Integer keySize, X509Certificate[] certs,String idStr)
154         {
155             this._keySize=keySize;
156             this._certs=certs;
157             this._idStr=idStr;
158         }
159 
160         X509Certificate[] getCerts()
161         {
162             return _certs;
163         }
164 
165         Integer getKeySize()
166         {
167             return _keySize;
168         }
169         
170         String getIdStr()
171         {
172             return _idStr;
173         }
174     }
175 
176 }