1 /* 2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.net.ssl.internal.www.protocol.https; 27 28 import java.net.URL; 29 import java.net.Proxy; 30 import java.io.IOException; 31 import java.util.Collection; 32 import java.util.List; 33 import java.util.Iterator; 34 35 import java.security.Principal; 36 import java.security.cert.*; 37 38 import javax.security.auth.x500.X500Principal; 39 40 import sun.security.util.HostnameChecker; 41 import sun.security.util.DerValue; 42 import sun.security.x509.X500Name; 43 44 import sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection; 45 46 /** 47 * This class was introduced to provide an additional level of 48 * abstraction between javax.net.ssl.HttpURLConnection and 49 * com.sun.net.ssl.HttpURLConnection objects. <p> 50 * 51 * javax.net.ssl.HttpURLConnection is used in the new sun.net version 52 * of protocol implementation (this one) 53 * com.sun.net.ssl.HttpURLConnection is used in the com.sun version. 54 * 55 */ 56 public class DelegateHttpsURLConnection extends AbstractDelegateHttpsURLConnection { 57 58 // we need a reference to the HttpsURLConnection to get 59 // the properties set there 60 // we also need it to be public so that it can be referenced 61 // from sun.net.www.protocol.http.HttpURLConnection 62 // this is for ResponseCache.put(URI, URLConnection) 63 // second parameter needs to be cast to javax.net.ssl.HttpsURLConnection 64 // instead of AbstractDelegateHttpsURLConnection 65 public com.sun.net.ssl.HttpsURLConnection httpsURLConnection; 66 DelegateHttpsURLConnection(URL url, sun.net.www.protocol.http.Handler handler, com.sun.net.ssl.HttpsURLConnection httpsURLConnection)67 DelegateHttpsURLConnection(URL url, 68 sun.net.www.protocol.http.Handler handler, 69 com.sun.net.ssl.HttpsURLConnection httpsURLConnection) 70 throws IOException { 71 this(url, null, handler, httpsURLConnection); 72 } 73 DelegateHttpsURLConnection(URL url, Proxy p, sun.net.www.protocol.http.Handler handler, com.sun.net.ssl.HttpsURLConnection httpsURLConnection)74 DelegateHttpsURLConnection(URL url, Proxy p, 75 sun.net.www.protocol.http.Handler handler, 76 com.sun.net.ssl.HttpsURLConnection httpsURLConnection) 77 throws IOException { 78 super(url, p, handler); 79 this.httpsURLConnection = httpsURLConnection; 80 } 81 getSSLSocketFactory()82 protected javax.net.ssl.SSLSocketFactory getSSLSocketFactory() { 83 return httpsURLConnection.getSSLSocketFactory(); 84 } 85 getHostnameVerifier()86 protected javax.net.ssl.HostnameVerifier getHostnameVerifier() { 87 // note: getHostnameVerifier() never returns null 88 return new VerifierWrapper(httpsURLConnection.getHostnameVerifier()); 89 } 90 91 /* 92 * Called by layered delegator's finalize() method to handle closing 93 * the underlying object. 94 */ dispose()95 protected void dispose() throws Throwable { 96 super.finalize(); 97 } 98 } 99 100 class VerifierWrapper implements javax.net.ssl.HostnameVerifier { 101 102 private com.sun.net.ssl.HostnameVerifier verifier; 103 VerifierWrapper(com.sun.net.ssl.HostnameVerifier verifier)104 VerifierWrapper(com.sun.net.ssl.HostnameVerifier verifier) { 105 this.verifier = verifier; 106 } 107 108 /* 109 * In com.sun.net.ssl.HostnameVerifier the method is defined 110 * as verify(String urlHostname, String certHostname). 111 * This means we need to extract the hostname from the X.509 certificate 112 * or from the Kerberos principal name, in this wrapper. 113 */ verify(String hostname, javax.net.ssl.SSLSession session)114 public boolean verify(String hostname, javax.net.ssl.SSLSession session) { 115 try { 116 String serverName; 117 // Use ciphersuite to determine whether Kerberos is active. 118 if (session.getCipherSuite().startsWith("TLS_KRB5")) { 119 serverName = 120 HostnameChecker.getServerName(getPeerPrincipal(session)); 121 122 } else { // X.509 123 Certificate[] serverChain = session.getPeerCertificates(); 124 if ((serverChain == null) || (serverChain.length == 0)) { 125 return false; 126 } 127 if (serverChain[0] instanceof X509Certificate == false) { 128 return false; 129 } 130 X509Certificate serverCert = (X509Certificate)serverChain[0]; 131 serverName = getServername(serverCert); 132 } 133 if (serverName == null) { 134 return false; 135 } 136 return verifier.verify(hostname, serverName); 137 } catch (javax.net.ssl.SSLPeerUnverifiedException e) { 138 return false; 139 } 140 } 141 142 /* 143 * Get the peer principal from the session 144 */ getPeerPrincipal(javax.net.ssl.SSLSession session)145 private Principal getPeerPrincipal(javax.net.ssl.SSLSession session) 146 throws javax.net.ssl.SSLPeerUnverifiedException 147 { 148 Principal principal; 149 try { 150 principal = session.getPeerPrincipal(); 151 } catch (AbstractMethodError e) { 152 // if the provider does not support it, return null, since 153 // we need it only for Kerberos. 154 principal = null; 155 } 156 return principal; 157 } 158 159 /* 160 * Extract the name of the SSL server from the certificate. 161 * 162 * Note this code is essentially a subset of the hostname extraction 163 * code in HostnameChecker. 164 */ getServername(X509Certificate peerCert)165 private static String getServername(X509Certificate peerCert) { 166 try { 167 // compare to subjectAltNames if dnsName is present 168 Collection<List<?>> subjAltNames = peerCert.getSubjectAlternativeNames(); 169 if (subjAltNames != null) { 170 for (Iterator<List<?>> itr = subjAltNames.iterator(); itr.hasNext(); ) { 171 List<?> next = itr.next(); 172 if (((Integer)next.get(0)).intValue() == 2) { 173 // compare dNSName with host in url 174 String dnsName = ((String)next.get(1)); 175 return dnsName; 176 } 177 } 178 } 179 180 // else check against common name in the subject field 181 X500Name subject = HostnameChecker.getSubjectX500Name(peerCert); 182 183 DerValue derValue = subject.findMostSpecificAttribute 184 (X500Name.commonName_oid); 185 if (derValue != null) { 186 try { 187 String name = derValue.getAsString(); 188 return name; 189 } catch (IOException e) { 190 // ignore 191 } 192 } 193 } catch (java.security.cert.CertificateException e) { 194 // ignore 195 } 196 return null; 197 } 198 199 } 200