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 @SuppressWarnings("deprecation") // HttpsURLConnection is deprecated 57 public class DelegateHttpsURLConnection extends AbstractDelegateHttpsURLConnection { 58 59 // we need a reference to the HttpsURLConnection to get 60 // the properties set there 61 // we also need it to be public so that it can be referenced 62 // from sun.net.www.protocol.http.HttpURLConnection 63 // this is for ResponseCache.put(URI, URLConnection) 64 // second parameter needs to be cast to javax.net.ssl.HttpsURLConnection 65 // instead of AbstractDelegateHttpsURLConnection 66 67 public com.sun.net.ssl.HttpsURLConnection httpsURLConnection; 68 69 DelegateHttpsURLConnection(URL url, 70 sun.net.www.protocol.http.Handler handler, 71 com.sun.net.ssl.HttpsURLConnection httpsURLConnection) 72 throws IOException { 73 this(url, null, handler, httpsURLConnection); 74 } 75 76 DelegateHttpsURLConnection(URL url, Proxy p, 77 sun.net.www.protocol.http.Handler handler, 78 com.sun.net.ssl.HttpsURLConnection httpsURLConnection) 79 throws IOException { 80 super(url, p, handler); 81 this.httpsURLConnection = httpsURLConnection; 82 } 83 84 protected javax.net.ssl.SSLSocketFactory getSSLSocketFactory() { 85 return httpsURLConnection.getSSLSocketFactory(); 86 } 87 88 protected javax.net.ssl.HostnameVerifier getHostnameVerifier() { 89 // note: getHostnameVerifier() never returns null 90 return new VerifierWrapper(httpsURLConnection.getHostnameVerifier()); 91 } 92 93 /* 94 * Called by layered delegator's finalize() method to handle closing 95 * the underlying object. 96 */ 97 protected void dispose() throws Throwable { 98 super.finalize(); 99 } 100 } 101 102 class VerifierWrapper implements javax.net.ssl.HostnameVerifier { 103 @SuppressWarnings("deprecation") 104 private com.sun.net.ssl.HostnameVerifier verifier; 105 106 @SuppressWarnings("deprecation") 107 VerifierWrapper(com.sun.net.ssl.HostnameVerifier verifier) { 108 this.verifier = verifier; 109 } 110 111 /* 112 * In com.sun.net.ssl.HostnameVerifier the method is defined 113 * as verify(String urlHostname, String certHostname). 114 * This means we need to extract the hostname from the X.509 certificate 115 * or from the Kerberos principal name, in this wrapper. 116 */ 117 public boolean verify(String hostname, javax.net.ssl.SSLSession session) { 118 try { 119 String serverName; 120 // Use ciphersuite to determine whether Kerberos is active. 121 if (session.getCipherSuite().startsWith("TLS_KRB5")) { 122 serverName = 123 HostnameChecker.getServerName(getPeerPrincipal(session)); 124 125 } else { // X.509 126 Certificate[] serverChain = session.getPeerCertificates(); 127 if ((serverChain == null) || (serverChain.length == 0)) { 128 return false; 129 } 130 if (serverChain[0] instanceof X509Certificate == false) { 131 return false; 132 } 133 X509Certificate serverCert = (X509Certificate)serverChain[0]; 134 serverName = getServername(serverCert); 135 } 136 if (serverName == null) { 137 return false; 138 } 139 return verifier.verify(hostname, serverName); 140 } catch (javax.net.ssl.SSLPeerUnverifiedException e) { 141 return false; 142 } 143 } 144 145 /* 146 * Get the peer principal from the session 147 */ 148 private Principal getPeerPrincipal(javax.net.ssl.SSLSession session) 149 throws javax.net.ssl.SSLPeerUnverifiedException 150 { 151 Principal principal; 152 try { 153 principal = session.getPeerPrincipal(); 154 } catch (AbstractMethodError e) { 155 // if the provider does not support it, return null, since 156 // we need it only for Kerberos. 157 principal = null; 158 } 159 return principal; 160 } 161 162 /* 163 * Extract the name of the SSL server from the certificate. 164 * 165 * Note this code is essentially a subset of the hostname extraction 166 * code in HostnameChecker. 167 */ 168 private static String getServername(X509Certificate peerCert) { 169 try { 170 // compare to subjectAltNames if dnsName is present 171 Collection<List<?>> subjAltNames = peerCert.getSubjectAlternativeNames(); 172 if (subjAltNames != null) { 173 for (Iterator<List<?>> itr = subjAltNames.iterator(); itr.hasNext(); ) { 174 List<?> next = itr.next(); 175 if (((Integer)next.get(0)).intValue() == 2) { 176 // compare dNSName with host in url 177 String dnsName = ((String)next.get(1)); 178 return dnsName; 179 } 180 } 181 } 182 183 // else check against common name in the subject field 184 X500Name subject = HostnameChecker.getSubjectX500Name(peerCert); 185 186 DerValue derValue = subject.findMostSpecificAttribute 187 (X500Name.commonName_oid); 188 if (derValue != null) { 189 try { 190 String name = derValue.getAsString(); 191 return name; 192 } catch (IOException e) { 193 // ignore 194 } 195 } 196 } catch (java.security.cert.CertificateException e) { 197 // ignore 198 } 199 return null; 200 } 201 202 }