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