view src/org/eclipse/jetty/server/ssl/SslCertificates.java @ 873:220ad4853cda

remove StreamEndPoint
author Franklin Schmidt <fschmidt@gmail.com>
date Mon, 03 Oct 2016 20:03:50 -0600
parents 1c0b6841cd32
children 4dc1e1a18661
line wrap: on
line source

//
//  ========================================================================
//  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.server.Request;
import org.eclipse.jetty.util.TypeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SslCertificates
{
	private static final Logger LOG = LoggerFactory.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("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.
	 * @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("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;
		}
	}

}