1 2 3 /* 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 5 * 6 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. 7 * 8 * Portions Copyright Apache Software Foundation. 9 * 10 * The contents of this file are subject to the terms of either the GNU 11 * General Public License Version 2 only ("GPL") or the Common Development 12 * and Distribution License("CDDL") (collectively, the "License"). You 13 * may not use this file except in compliance with the License. You can obtain 14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html 15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific 16 * language governing permissions and limitations under the License. 17 * 18 * When distributing the software, include this License Header Notice in each 19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. 20 * Sun designates this particular file as subject to the "Classpath" exception 21 * as provided by Sun in the GPL Version 2 section of the License file that 22 * accompanied this code. If applicable, add the following below the License 23 * Header, with the fields enclosed by brackets [] replaced by your own 24 * identifying information: "Portions Copyrighted [year] 25 * [name of copyright owner]" 26 * 27 * Contributor(s): 28 * 29 * If you wish your version of this file to be governed by only the CDDL or 30 * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 * elects to include this software in this distribution under the [CDDL or GPL 32 * Version 2] license." If you don't indicate a single choice of license, a 33 * recipient has the option to distribute your version of this file under 34 * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 * its licensees as provided above. However, if you add GPL Version 2 code 36 * and therefore, elected the GPL Version 2 license, then the option applies 37 * only if the new code is made subject to such option by the copyright 38 * holder. 39 */ 40 41 package org.apache.tomcat.util.net.jsse; 42 43 import org.apache.tomcat.util.net.SSLSupport; 44 import java.io; 45 import java.net; 46 import java.util.Vector; 47 import java.security.cert.CertificateFactory; 48 import java.security.cert.X509Certificate; 49 import java.security.cert.Certificate; 50 import javax.net.ssl.SSLSession; 51 import javax.net.ssl.SSLSocket; 52 import javax.net.ssl.SSLException; 53 import javax.net.ssl.HandshakeCompletedListener; 54 import javax.net.ssl.HandshakeCompletedEvent; 55 import java.security.cert.CertificateFactory; 56 // START SJSAS 6439313 57 import javax.net.ssl.SSLEngine; 58 // END SJSAS 6439313 59 60 /* JSSESupport 61 62 Concrete implementation class for JSSE 63 Support classes. 64 65 This will only work with JDK 1.2 and up since it 66 depends on JDK 1.2's certificate support 67 68 @author EKR 69 @author Craig R. McClanahan 70 Parts cribbed from JSSECertCompat 71 Parts cribbed from CertificatesValve 72 */ 73 74 class JSSE14Support extends JSSESupport { 75 76 private static com.sun.org.apache.commons.logging.Log logger = 77 com.sun.org.apache.commons.logging.LogFactory.getLog(JSSE14Support.class); 78 79 Listener listener = new Listener(); 80 81 public JSSE14Support(SSLSocket sock){ 82 super(sock); 83 sock.addHandshakeCompletedListener(listener); 84 } 85 86 // START SJSAS 6439313 87 public JSSE14Support(SSLEngine sslEngine){ 88 super(sslEngine); 89 } 90 // END SJSAS 6439313 91 92 protected void handShake() throws IOException { 93 ssl.setNeedClientAuth(true); 94 synchronousHandshake(ssl); 95 } 96 97 /** 98 * JSSE in JDK 1.4 has an issue/feature that requires us to do a 99 * read() to get the client-cert. As suggested by Andreas 100 * Sterbenz 101 */ 102 private void synchronousHandshake(SSLSocket socket) 103 throws IOException { 104 InputStream in = socket.getInputStream(); 105 int oldTimeout = socket.getSoTimeout(); 106 socket.setSoTimeout(1000); 107 byte[] b = new byte[0]; 108 listener.reset(); 109 socket.startHandshake(); 110 int maxTries = 60; // 60 * 1000 = example 1 minute time out 111 for (int i = 0; i < maxTries; i++) { 112 if(logger.isTraceEnabled()) 113 logger.trace("Reading for try #" +i); 114 try { 115 int x = in.read(b); 116 } catch(SSLException sslex) { 117 logger.info("SSL Error getting client Certs",sslex); 118 throw sslex; 119 } catch (IOException e) { 120 // ignore - presumably the timeout 121 } 122 if (listener.completed) { 123 break; 124 } 125 } 126 socket.setSoTimeout(oldTimeout); 127 if (listener.completed == false) { 128 throw new SocketException("SSL Cert handshake timeout"); 129 } 130 } 131 132 /** Return the X509certificates or null if we can't get them. 133 * XXX We should allow unverified certificates 134 */ 135 protected X509Certificate [] getX509Certificates(SSLSession session) 136 throws IOException 137 { 138 Certificate [] certs=null; 139 try { 140 certs = session.getPeerCertificates(); 141 } catch( Throwable t ) { 142 logger.debug("Error getting client certs",t); 143 return null; 144 } 145 if( certs==null ) return null; 146 147 X509Certificate [] x509Certs = new X509Certificate[certs.length]; 148 for(int i=0; i < certs.length; i++) { 149 if( certs[i] instanceof X509Certificate ) { 150 // always currently true with the JSSE 1.1.x 151 x509Certs[i] = (X509Certificate)certs[i]; 152 } else { 153 try { 154 byte [] buffer = certs[i].getEncoded(); 155 CertificateFactory cf = 156 CertificateFactory.getInstance("X.509"); 157 ByteArrayInputStream stream = 158 new ByteArrayInputStream(buffer); 159 x509Certs[i] = (X509Certificate) 160 cf.generateCertificate(stream); 161 } catch(Exception ex) { 162 logger.info("Error translating cert " + certs[i], ex); 163 return null; 164 } 165 } 166 if(logger.isTraceEnabled()) 167 logger.trace("Cert #" + i + " = " + x509Certs[i]); 168 } 169 if(x509Certs.length < 1) 170 return null; 171 return x509Certs; 172 } 173 174 175 private static class Listener implements HandshakeCompletedListener { 176 volatile boolean completed = false; 177 public void handshakeCompleted(HandshakeCompletedEvent event) { 178 completed = true; 179 } 180 void reset() { 181 completed = false; 182 } 183 } 184 185 } 186