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