Home | History | Annotate | Download | only in ssl
      1 //
      2 //  ========================================================================
      3 //  Copyright (c) 1995-2014 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 }
    183