View Javadoc

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