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