View Javadoc

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