blob: 655b814ec7f916421121684f2a666074f53343d8 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server.ssl;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.http.HttpSchemes;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.bio.SocketEndPoint;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class SslCertificates
{
private static final Logger LOG = Log.getLogger(SslCertificates.class);
/**
* The name of the SSLSession attribute that will contain any cached information.
*/
static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
public static X509Certificate[] getCertChain(SSLSession sslSession)
{
try
{
javax.security.cert.X509Certificate javaxCerts[]=sslSession.getPeerCertificateChain();
if (javaxCerts==null||javaxCerts.length==0)
return null;
int length=javaxCerts.length;
X509Certificate[] javaCerts=new X509Certificate[length];
java.security.cert.CertificateFactory cf=java.security.cert.CertificateFactory.getInstance("X.509");
for (int i=0; i<length; i++)
{
byte bytes[]=javaxCerts[i].getEncoded();
ByteArrayInputStream stream=new ByteArrayInputStream(bytes);
javaCerts[i]=(X509Certificate)cf.generateCertificate(stream);
}
return javaCerts;
}
catch (SSLPeerUnverifiedException pue)
{
return null;
}
catch (Exception e)
{
LOG.warn(Log.EXCEPTION,e);
return null;
}
}
/* ------------------------------------------------------------ */
/**
* Allow the Listener a chance to customise the request. before the server
* does its stuff. <br>
* This allows the required attributes to be set for SSL requests. <br>
* The requirements of the Servlet specs are:
* <ul>
* <li> an attribute named "javax.servlet.request.ssl_session_id" of type
* String (since Servlet Spec 3.0).</li>
* <li> an attribute named "javax.servlet.request.cipher_suite" of type
* String.</li>
* <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
* <li> an attribute named "javax.servlet.request.X509Certificate" of type
* java.security.cert.X509Certificate[]. This is an array of objects of type
* X509Certificate, the order of this array is defined as being in ascending
* order of trust. The first certificate in the chain is the one set by the
* client, the next is the one used to authenticate the first, and so on.
* </li>
* </ul>
*
* @param endpoint
* The Socket the request arrived on. This should be a
* {@link SocketEndPoint} wrapping a {@link SSLSocket}.
* @param request
* HttpRequest to be customised.
*/
public static void customize(SSLSession sslSession, EndPoint endpoint, Request request) throws IOException
{
request.setScheme(HttpSchemes.HTTPS);
try
{
String cipherSuite=sslSession.getCipherSuite();
Integer keySize;
X509Certificate[] certs;
String idStr;
CachedInfo cachedInfo=(CachedInfo)sslSession.getValue(CACHED_INFO_ATTR);
if (cachedInfo!=null)
{
keySize=cachedInfo.getKeySize();
certs=cachedInfo.getCerts();
idStr=cachedInfo.getIdStr();
}
else
{
keySize=new Integer(ServletSSL.deduceKeyLength(cipherSuite));
certs=SslCertificates.getCertChain(sslSession);
byte[] bytes = sslSession.getId();
idStr = TypeUtil.toHexString(bytes);
cachedInfo=new CachedInfo(keySize,certs,idStr);
sslSession.putValue(CACHED_INFO_ATTR,cachedInfo);
}
if (certs!=null)
request.setAttribute("javax.servlet.request.X509Certificate",certs);
request.setAttribute("javax.servlet.request.cipher_suite",cipherSuite);
request.setAttribute("javax.servlet.request.key_size",keySize);
request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
}
catch (Exception e)
{
LOG.warn(Log.EXCEPTION,e);
}
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/**
* Simple bundle of information that is cached in the SSLSession. Stores the
* effective keySize and the client certificate chain.
*/
private static class CachedInfo
{
private final X509Certificate[] _certs;
private final Integer _keySize;
private final String _idStr;
CachedInfo(Integer keySize, X509Certificate[] certs,String idStr)
{
this._keySize=keySize;
this._certs=certs;
this._idStr=idStr;
}
X509Certificate[] getCerts()
{
return _certs;
}
Integer getKeySize()
{
return _keySize;
}
String getIdStr()
{
return _idStr;
}
}
}