All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tomcat.util.net.jsse.JSSESupport Maven / Gradle / Ivy

There is a newer version: 1.0.b11
Show newest version
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.apache.tomcat.util.net.jsse;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Map;
import java.util.WeakHashMap;

import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.security.cert.X509Certificate;

import org.apache.tomcat.util.net.SSLSessionManager;
import org.apache.tomcat.util.net.SSLSupport;

/** JSSESupport

   Concrete implementation class for JSSE
   Support classes.

   This will only work with JDK 1.2 and up since it
   depends on JDK 1.2's certificate support

   @author EKR
   @author Craig R. McClanahan
   @author Filip Hanik
   Parts cribbed from JSSECertCompat       
   Parts cribbed from CertificatesValve
*/

class JSSESupport implements SSLSupport, SSLSessionManager {
    
    private static final org.apache.juli.logging.Log log =
        org.apache.juli.logging.LogFactory.getLog(JSSESupport.class);
    
    private static final Map keySizeCache =
        new WeakHashMap();

    protected SSLSocket ssl;
    protected SSLSession session;

    Listener listener = new Listener();

    JSSESupport(SSLSocket sock){
        ssl=sock;
        session = sock.getSession();
        sock.addHandshakeCompletedListener(listener);
    }
    
    JSSESupport(SSLSession session) {
        this.session = session;
    }

    @Override
    public String getCipherSuite() throws IOException {
        // Look up the current SSLSession
        if (session == null)
            return null;
        return session.getCipherSuite();
    }

    @Override
    public Object[] getPeerCertificateChain() 
        throws IOException {
        return getPeerCertificateChain(false);
    }

    protected java.security.cert.X509Certificate [] getX509Certificates(
            SSLSession session) {
        Certificate [] certs=null;
        try {
            certs = session.getPeerCertificates();
        } catch( Throwable t ) {
            log.debug("Error getting client certs",t);
            return null;
        }
        if( certs==null ) return null;
        
        java.security.cert.X509Certificate [] x509Certs = 
            new java.security.cert.X509Certificate[certs.length];
        for(int i=0; i < certs.length; i++) {
            if (certs[i] instanceof java.security.cert.X509Certificate ) {
                // always currently true with the JSSE 1.1.x
                x509Certs[i] = (java.security.cert.X509Certificate) certs[i];
            } else {
                try {
                    byte [] buffer = certs[i].getEncoded();
                    CertificateFactory cf =
                        CertificateFactory.getInstance("X.509");
                    ByteArrayInputStream stream =
                        new ByteArrayInputStream(buffer);
                    x509Certs[i] = (java.security.cert.X509Certificate)
                            cf.generateCertificate(stream);
                } catch(Exception ex) { 
                    log.info("Error translating cert " + certs[i], ex);
                    return null;
                }
            }
            if(log.isTraceEnabled())
                log.trace("Cert #" + i + " = " + x509Certs[i]);
        }
        if(x509Certs.length < 1)
            return null;
        return x509Certs;
    }

    @Override
    public Object[] getPeerCertificateChain(boolean force)
        throws IOException {
        // Look up the current SSLSession
        if (session == null)
            return null;

        // Convert JSSE's certificate format to the ones we need
        X509Certificate [] jsseCerts = null;
        try {
            jsseCerts = session.getPeerCertificateChain();
        } catch(Exception bex) {
            // ignore.
        }
        if (jsseCerts == null)
            jsseCerts = new X509Certificate[0];
        if(jsseCerts.length <= 0 && force) {
            session.invalidate();
            handShake();
            session = ssl.getSession();
        }
        return getX509Certificates(session);
    }

    protected void handShake() throws IOException {
        if( ssl.getWantClientAuth() ) {
            log.debug("No client cert sent for want");
        } else {
            ssl.setNeedClientAuth(true);
        }

        if (ssl.getEnabledCipherSuites().length == 0) {
            // Handshake is never going to be successful.
            // Assume this is because handshakes are disabled
            log.warn("SSL server initiated renegotiation is disabled, closing connection");
            session.invalidate();
            ssl.close();
            return;
        }

        InputStream in = ssl.getInputStream();
        int oldTimeout = ssl.getSoTimeout();
        ssl.setSoTimeout(1000);
        byte[] b = new byte[0];
        listener.reset();
        ssl.startHandshake();
        int maxTries = 60; // 60 * 1000 = example 1 minute time out
        for (int i = 0; i < maxTries; i++) {
            if (log.isTraceEnabled())
                log.trace("Reading for try #" + i);
            try {
                in.read(b);
            } catch(SSLException sslex) {
                log.info("SSL Error getting client Certs",sslex);
                throw sslex;
            } catch (IOException e) {
                // ignore - presumably the timeout
            }
            if (listener.completed) {
                break;
            }
        }
        ssl.setSoTimeout(oldTimeout);
        if (listener.completed == false) {
            throw new SocketException("SSL Cert handshake timeout");
        }

    }

    /**
     * Copied from org.apache.catalina.valves.CertificateValve
     */
    @Override
    public Integer getKeySize() 
        throws IOException {
        // Look up the current SSLSession
        SSLSupport.CipherData c_aux[]=ciphers;
        if (session == null)
            return null;
        
        Integer keySize = null;
        synchronized(keySizeCache) {
            keySize = keySizeCache.get(session);
        }
        
        if (keySize == null) {
            int size = 0;
            String cipherSuite = session.getCipherSuite();
            for (int i = 0; i < c_aux.length; i++) {
                if (cipherSuite.indexOf(c_aux[i].phrase) >= 0) {
                    size = c_aux[i].keySize;
                    break;
                }
            }
            keySize = new Integer(size);
            synchronized(keySizeCache) {
                keySizeCache.put(session, keySize);
            }
        }
        return keySize;
    }

    @Override
    public String getSessionId()
        throws IOException {
        // Look up the current SSLSession
        if (session == null)
            return null;
        // Expose ssl_session (getId)
        byte [] ssl_session = session.getId();
        if ( ssl_session == null) 
            return null;
        StringBuilder buf=new StringBuilder();
        for(int x=0; x2) digit=digit.substring(digit.length()-2);
            buf.append(digit);
        }
        return buf.toString();
    }


    private static class Listener implements HandshakeCompletedListener {
        volatile boolean completed = false;
        @Override
        public void handshakeCompleted(HandshakeCompletedEvent event) {
            completed = true;
        }
        void reset() {
            completed = false;
        }
    }

    /**
     * Invalidate the session this support object is associated with.
     */
    @Override
    public void invalidateSession() {
        session.invalidate();
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy