457 lines
18 KiB
Java
457 lines
18 KiB
Java
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package javax.net.ssl;
|
|
|
|
import java.net.URL;
|
|
import java.net.HttpURLConnection;
|
|
import java.security.Principal;
|
|
import java.security.cert.X509Certificate;
|
|
|
|
/**
|
|
* <code>HttpsURLConnection</code> extends <code>HttpURLConnection</code>
|
|
* with support for https-specific features.
|
|
* <P>
|
|
* See <A HREF="http://www.w3.org/pub/WWW/Protocols/">
|
|
* http://www.w3.org/pub/WWW/Protocols/</A> and
|
|
* <A HREF="http://www.ietf.org/"> RFC 2818 </A>
|
|
* for more details on the
|
|
* https specification.
|
|
* <P>
|
|
* This class uses <code>HostnameVerifier</code> and
|
|
* <code>SSLSocketFactory</code>.
|
|
* There are default implementations defined for both classes.
|
|
* However, the implementations can be replaced on a per-class (static) or
|
|
* per-instance basis. All new <code>HttpsURLConnection</code>s instances
|
|
* will be assigned
|
|
* the "default" static values at instance creation, but they can be overriden
|
|
* by calling the appropriate per-instance set method(s) before
|
|
* <code>connect</code>ing.
|
|
*
|
|
* @since 1.4
|
|
*/
|
|
abstract public
|
|
class HttpsURLConnection extends HttpURLConnection
|
|
{
|
|
/**
|
|
* Creates an <code>HttpsURLConnection</code> using the
|
|
* URL specified.
|
|
*
|
|
* @param url the URL
|
|
*/
|
|
protected HttpsURLConnection(URL url) {
|
|
super(url);
|
|
}
|
|
|
|
/**
|
|
* Returns the cipher suite in use on this connection.
|
|
*
|
|
* @return the cipher suite
|
|
* @throws IllegalStateException if this method is called before
|
|
* the connection has been established.
|
|
*/
|
|
public abstract String getCipherSuite();
|
|
|
|
/**
|
|
* Returns the certificate(s) that were sent to the server during
|
|
* handshaking.
|
|
* <P>
|
|
* Note: This method is useful only when using certificate-based
|
|
* cipher suites.
|
|
* <P>
|
|
* When multiple certificates are available for use in a
|
|
* handshake, the implementation chooses what it considers the
|
|
* "best" certificate chain available, and transmits that to
|
|
* the other side. This method allows the caller to know
|
|
* which certificate chain was actually sent.
|
|
*
|
|
* @return an ordered array of certificates,
|
|
* with the client's own certificate first followed by any
|
|
* certificate authorities. If no certificates were sent,
|
|
* then null is returned.
|
|
* @throws IllegalStateException if this method is called before
|
|
* the connection has been established.
|
|
* @see #getLocalPrincipal()
|
|
*/
|
|
public abstract java.security.cert.Certificate [] getLocalCertificates();
|
|
|
|
/**
|
|
* Returns the server's certificate chain which was established
|
|
* as part of defining the session.
|
|
* <P>
|
|
* Note: This method can be used only when using certificate-based
|
|
* cipher suites; using it with non-certificate-based cipher suites,
|
|
* such as Kerberos, will throw an SSLPeerUnverifiedException.
|
|
*
|
|
* @return an ordered array of server certificates,
|
|
* with the peer's own certificate first followed by
|
|
* any certificate authorities.
|
|
* @throws SSLPeerUnverifiedException if the peer is not verified.
|
|
* @throws IllegalStateException if this method is called before
|
|
* the connection has been established.
|
|
* @see #getPeerPrincipal()
|
|
*/
|
|
public abstract java.security.cert.Certificate [] getServerCertificates()
|
|
throws SSLPeerUnverifiedException;
|
|
|
|
/**
|
|
* Returns the server's principal which was established as part of
|
|
* defining the session.
|
|
* <P>
|
|
* Note: Subclasses should override this method. If not overridden, it
|
|
* will default to returning the X500Principal of the server's end-entity
|
|
* certificate for certificate-based ciphersuites, or throw an
|
|
* SSLPeerUnverifiedException for non-certificate based ciphersuites,
|
|
* such as Kerberos.
|
|
*
|
|
* @return the server's principal. Returns an X500Principal of the
|
|
* end-entity certiticate for X509-based cipher suites, and
|
|
* KerberosPrincipal for Kerberos cipher suites.
|
|
*
|
|
* @throws SSLPeerUnverifiedException if the peer was not verified
|
|
* @throws IllegalStateException if this method is called before
|
|
* the connection has been established.
|
|
*
|
|
* @see #getServerCertificates()
|
|
* @see #getLocalPrincipal()
|
|
*
|
|
* @since 1.5
|
|
*/
|
|
public Principal getPeerPrincipal()
|
|
throws SSLPeerUnverifiedException {
|
|
|
|
java.security.cert.Certificate[] certs = getServerCertificates();
|
|
return ((X509Certificate)certs[0]).getSubjectX500Principal();
|
|
}
|
|
|
|
/**
|
|
* Returns the principal that was sent to the server during handshaking.
|
|
* <P>
|
|
* Note: Subclasses should override this method. If not overridden, it
|
|
* will default to returning the X500Principal of the end-entity certificate
|
|
* that was sent to the server for certificate-based ciphersuites or,
|
|
* return null for non-certificate based ciphersuites, such as Kerberos.
|
|
*
|
|
* @return the principal sent to the server. Returns an X500Principal
|
|
* of the end-entity certificate for X509-based cipher suites, and
|
|
* KerberosPrincipal for Kerberos cipher suites. If no principal was
|
|
* sent, then null is returned.
|
|
*
|
|
* @throws IllegalStateException if this method is called before
|
|
* the connection has been established.
|
|
*
|
|
* @see #getLocalCertificates()
|
|
* @see #getPeerPrincipal()
|
|
*
|
|
* @since 1.5
|
|
*/
|
|
public Principal getLocalPrincipal() {
|
|
|
|
java.security.cert.Certificate[] certs = getLocalCertificates();
|
|
if (certs != null) {
|
|
return ((X509Certificate)certs[0]).getSubjectX500Principal();
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// BEGIN Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
|
|
// The RI default hostname verifier is a static member of the class, which means
|
|
// it's created when the class is initialized. As well, its default verifier
|
|
// just fails all verification attempts, whereas we use OkHttp's verifier.
|
|
/*
|
|
* Holds the default instance so class preloading doesn't create an instance of
|
|
* it.
|
|
*/
|
|
private static final String OK_HOSTNAME_VERIFIER_CLASS
|
|
= "com.android.okhttp.internal.tls.OkHostnameVerifier";
|
|
private static class NoPreloadHolder {
|
|
public static HostnameVerifier defaultHostnameVerifier;
|
|
static {
|
|
try {
|
|
/**
|
|
* <code>HostnameVerifier</code> provides a callback mechanism so that
|
|
* implementers of this interface can supply a policy for
|
|
* handling the case where the host to connect to and
|
|
* the server name from the certificate mismatch.
|
|
*/
|
|
defaultHostnameVerifier = (HostnameVerifier)
|
|
Class.forName(OK_HOSTNAME_VERIFIER_CLASS)
|
|
.getField("INSTANCE").get(null);
|
|
} catch (Exception e) {
|
|
throw new AssertionError("Failed to obtain okhttp HostnameVerifier", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The <code>hostnameVerifier</code> for this object.
|
|
*/
|
|
protected HostnameVerifier hostnameVerifier = NoPreloadHolder.defaultHostnameVerifier;
|
|
// END Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
|
|
|
|
// Android-changed: Modified the documentation to explain side effects / discourage method use.
|
|
/**
|
|
* Sets the default <code>HostnameVerifier</code> inherited by a
|
|
* new instance of this class.
|
|
* <p>
|
|
* Developers are <em>strongly</em> discouraged from changing the default
|
|
* {@code HostnameVerifier} as {@link #getDefaultHostnameVerifier()} is used by several
|
|
* classes for hostname verification on Android.
|
|
* <table>
|
|
* <tr>
|
|
* <th>User</th>
|
|
* <th>Effect</th>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>Android's default {@link TrustManager}, as used with Android's default
|
|
* {@link SSLContext}, {@link SSLSocketFactory} and {@link SSLSocket} implementations.
|
|
* </td>
|
|
* <td>The {@code HostnameVerifier} is used to verify the peer's
|
|
* certificate hostname after connecting if {@code
|
|
* SSLParameters.setEndpointIdentificationAlgorithm("HTTPS")} has been called.
|
|
* Instances use the <em>current</em> default {@code HostnameVerifier} at verification
|
|
* time.</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link android.net.SSLCertificateSocketFactory}</td>
|
|
* <td>The current default {@code HostnameVerifier} is used from various {@code
|
|
* createSocket} methods. See {@link android.net.SSLCertificateSocketFactory} for
|
|
* details; for example {@link
|
|
* android.net.SSLCertificateSocketFactory#createSocket(String, int)}.
|
|
* </td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>Android's default {@link HttpsURLConnection} implementation.</td>
|
|
* <td>The {@code HostnameVerifier} is used after a successful TLS handshake to verify
|
|
* the URI host against the TLS session server. Instances use the default {@code
|
|
* HostnameVerifier} set <em>when they were created</em> unless overridden with {@link
|
|
* #setHostnameVerifier(HostnameVerifier)}.
|
|
* Android's <code>HttpsURLConnection</code> relies on the {@code HostnameVerifier}
|
|
* for the <em>entire</em> hostname verification step.</td>
|
|
* </tr>
|
|
* </table>
|
|
* <p>
|
|
* If this method is not called, the default <code>HostnameVerifier</code> will check the
|
|
* hostname according to RFC 2818.
|
|
*
|
|
* @param v the default host name verifier
|
|
* @throws IllegalArgumentException if the <code>HostnameVerifier</code>
|
|
* parameter is null.
|
|
* @throws SecurityException if a security manager exists and its
|
|
* <code>checkPermission</code> method does not allow
|
|
* <code>SSLPermission("setHostnameVerifier")</code>
|
|
* @see #getDefaultHostnameVerifier()
|
|
*/
|
|
public static void setDefaultHostnameVerifier(HostnameVerifier v) {
|
|
if (v == null) {
|
|
throw new IllegalArgumentException(
|
|
"no default HostnameVerifier specified");
|
|
}
|
|
|
|
SecurityManager sm = System.getSecurityManager();
|
|
if (sm != null) {
|
|
sm.checkPermission(new SSLPermission("setHostnameVerifier"));
|
|
}
|
|
// Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
|
|
// defaultHostnameVerifier = v;
|
|
NoPreloadHolder.defaultHostnameVerifier = v;
|
|
}
|
|
|
|
/**
|
|
* Gets the default <code>HostnameVerifier</code> that is inherited
|
|
* by new instances of this class.
|
|
*
|
|
* @return the default host name verifier
|
|
* @see #setDefaultHostnameVerifier(HostnameVerifier)
|
|
*/
|
|
public static HostnameVerifier getDefaultHostnameVerifier() {
|
|
// Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
|
|
// return defaultHostnameVerifier;
|
|
return NoPreloadHolder.defaultHostnameVerifier;
|
|
}
|
|
|
|
// Android-changed: Modified the documentation to explain Android behavior.
|
|
/**
|
|
* Sets the <code>HostnameVerifier</code> for this instance.
|
|
* <P>
|
|
* New instances of this class inherit the default static hostname
|
|
* verifier set by {@link #setDefaultHostnameVerifier(HostnameVerifier)
|
|
* setDefaultHostnameVerifier}. Calls to this method replace
|
|
* this object's <code>HostnameVerifier</code>.
|
|
* <p>
|
|
* Android's <code>HttpsURLConnection</code> relies on the {@code HostnameVerifier}
|
|
* for the <em>entire</em> hostname verification step.
|
|
*
|
|
* @param v the host name verifier
|
|
* @throws IllegalArgumentException if the <code>HostnameVerifier</code>
|
|
* parameter is null.
|
|
* @see #getHostnameVerifier()
|
|
* @see #setDefaultHostnameVerifier(HostnameVerifier)
|
|
*/
|
|
public void setHostnameVerifier(HostnameVerifier v) {
|
|
if (v == null) {
|
|
throw new IllegalArgumentException(
|
|
"no HostnameVerifier specified");
|
|
}
|
|
|
|
hostnameVerifier = v;
|
|
}
|
|
|
|
// BEGIN Android-added: Core platform API to obtain a strict hostname verifier
|
|
/**
|
|
* Obtains a stricter {@code HostnameVerifier}.
|
|
*
|
|
* The {@code HostnameVerifier} returned by this method will reject certificates
|
|
* with wildcards for top-level domains such "*.com".
|
|
*
|
|
* This is a vendor hook (called from Zygote init code) to allow stricter hostname
|
|
* checking on NIAP-certified devices.
|
|
*
|
|
* @see com.squareup.okhttp.internal.tls.OkHostnameVerifier
|
|
*
|
|
* @hide
|
|
*/
|
|
public static HostnameVerifier getStrictHostnameVerifier() {
|
|
try {
|
|
return (HostnameVerifier) Class
|
|
.forName(OK_HOSTNAME_VERIFIER_CLASS)
|
|
.getMethod("strictInstance")
|
|
.invoke(null);
|
|
} catch (Exception e) {
|
|
return null;
|
|
}
|
|
}
|
|
// END Android-added: Core platform API to obtain a strict hostname verifier
|
|
|
|
/**
|
|
* Gets the <code>HostnameVerifier</code> in place on this instance.
|
|
*
|
|
* @return the host name verifier
|
|
* @see #setHostnameVerifier(HostnameVerifier)
|
|
* @see #setDefaultHostnameVerifier(HostnameVerifier)
|
|
*/
|
|
public HostnameVerifier getHostnameVerifier() {
|
|
return hostnameVerifier;
|
|
}
|
|
|
|
private static SSLSocketFactory defaultSSLSocketFactory = null;
|
|
|
|
/**
|
|
* The <code>SSLSocketFactory</code> inherited when an instance
|
|
* of this class is created.
|
|
*/
|
|
private SSLSocketFactory sslSocketFactory = getDefaultSSLSocketFactory();
|
|
|
|
/**
|
|
* Sets the default <code>SSLSocketFactory</code> inherited by new
|
|
* instances of this class.
|
|
* <P>
|
|
* The socket factories are used when creating sockets for secure
|
|
* https URL connections.
|
|
*
|
|
* @param sf the default SSL socket factory
|
|
* @throws IllegalArgumentException if the SSLSocketFactory
|
|
* parameter is null.
|
|
* @throws SecurityException if a security manager exists and its
|
|
* <code>checkSetFactory</code> method does not allow
|
|
* a socket factory to be specified.
|
|
* @see #getDefaultSSLSocketFactory()
|
|
*/
|
|
public static void setDefaultSSLSocketFactory(SSLSocketFactory sf) {
|
|
if (sf == null) {
|
|
throw new IllegalArgumentException(
|
|
"no default SSLSocketFactory specified");
|
|
}
|
|
|
|
SecurityManager sm = System.getSecurityManager();
|
|
if (sm != null) {
|
|
sm.checkSetFactory();
|
|
}
|
|
defaultSSLSocketFactory = sf;
|
|
}
|
|
|
|
/**
|
|
* Gets the default static <code>SSLSocketFactory</code> that is
|
|
* inherited by new instances of this class.
|
|
* <P>
|
|
* The socket factories are used when creating sockets for secure
|
|
* https URL connections.
|
|
*
|
|
* @return the default <code>SSLSocketFactory</code>
|
|
* @see #setDefaultSSLSocketFactory(SSLSocketFactory)
|
|
*/
|
|
public static SSLSocketFactory getDefaultSSLSocketFactory() {
|
|
if (defaultSSLSocketFactory == null) {
|
|
defaultSSLSocketFactory =
|
|
(SSLSocketFactory)SSLSocketFactory.getDefault();
|
|
}
|
|
return defaultSSLSocketFactory;
|
|
}
|
|
|
|
/**
|
|
* Sets the <code>SSLSocketFactory</code> to be used when this instance
|
|
* creates sockets for secure https URL connections.
|
|
* <P>
|
|
* New instances of this class inherit the default static
|
|
* <code>SSLSocketFactory</code> set by
|
|
* {@link #setDefaultSSLSocketFactory(SSLSocketFactory)
|
|
* setDefaultSSLSocketFactory}. Calls to this method replace
|
|
* this object's <code>SSLSocketFactory</code>.
|
|
*
|
|
* @param sf the SSL socket factory
|
|
* @throws IllegalArgumentException if the <code>SSLSocketFactory</code>
|
|
* parameter is null.
|
|
* @throws SecurityException if a security manager exists and its
|
|
* <code>checkSetFactory</code> method does not allow
|
|
* a socket factory to be specified.
|
|
* @see #getSSLSocketFactory()
|
|
*/
|
|
public void setSSLSocketFactory(SSLSocketFactory sf) {
|
|
if (sf == null) {
|
|
throw new IllegalArgumentException(
|
|
"no SSLSocketFactory specified");
|
|
}
|
|
|
|
SecurityManager sm = System.getSecurityManager();
|
|
if (sm != null) {
|
|
sm.checkSetFactory();
|
|
}
|
|
sslSocketFactory = sf;
|
|
}
|
|
|
|
/**
|
|
* Gets the SSL socket factory to be used when creating sockets
|
|
* for secure https URL connections.
|
|
*
|
|
* @return the <code>SSLSocketFactory</code>
|
|
* @see #setSSLSocketFactory(SSLSocketFactory)
|
|
*/
|
|
public SSLSocketFactory getSSLSocketFactory() {
|
|
return sslSocketFactory;
|
|
}
|
|
}
|