The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one or more |
| 3 | * contributor license agreements. See the NOTICE file distributed with |
| 4 | * this work for additional information regarding copyright ownership. |
| 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 |
| 6 | * (the "License"); you may not use this file except in compliance with |
| 7 | * the License. You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | package javax.net.ssl; |
| 19 | |
| 20 | import java.net.HttpURLConnection; |
| 21 | import java.net.URL; |
| 22 | import java.security.Principal; |
| 23 | import java.security.cert.Certificate; |
| 24 | import java.security.cert.X509Certificate; |
| 25 | |
| 26 | /** |
Brian Carlstrom | 8bccf8c | 2011-04-11 17:09:07 -0700 | [diff] [blame] | 27 | * An {@link HttpURLConnection} for HTTPS (<a |
| 28 | * href="http://tools.ietf.org/html/rfc2818">RFC 2818</a>). A |
| 29 | * connected {@code HttpsURLConnection} allows access to the |
| 30 | * negotiated cipher suite, the server certificate chain, and the |
| 31 | * client certificate chain if any. |
| 32 | * |
| 33 | * <h3>Providing an application specific X509TrustManager</h3> |
| 34 | * |
| 35 | * If an application wants to trust Certificate Authority (CA) |
| 36 | * certificates that are not part of the system, it should specify its |
| 37 | * own {@code X509TrustManager} via a {@code SSLSocketFactory} set on |
| 38 | * the {@code HttpsURLConnection}. The {@code X509TrustManager} can be |
| 39 | * created based on a {@code KeyStore} using a {@code |
| 40 | * TrustManagerFactory} to supply trusted CA certificates. Note that |
| 41 | * self-signed certificates are effectively their own CA and can be |
| 42 | * trusted by including them in a {@code KeyStore}. |
| 43 | * |
| 44 | * <p>For example, to trust a set of certificates specified by a {@code KeyStore}: |
| 45 | * <pre> {@code |
| 46 | * KeyStore keyStore = ...; |
| 47 | * TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); |
| 48 | * tmf.init(keyStore); |
| 49 | * |
| 50 | * SSLContext context = SSLContext.getInstance("TLS"); |
| 51 | * context.init(null, tmf.getTrustManagers(), null); |
| 52 | * |
| 53 | * URL url = new URL("https://www.example.com/"); |
| 54 | * HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); |
| 55 | * urlConnection.setSSLSocketFactory(context.getSocketFactory()); |
| 56 | * InputStream in = urlConnection.getInputStream(); |
| 57 | * }</pre> |
| 58 | * |
| 59 | * <p>It is possible to implement {@code X509TrustManager} directly |
| 60 | * instead of using one created by a {@code |
| 61 | * TrustManagerFactory}. While this is straightforward in the insecure |
| 62 | * case of allowing all certificate chains to pass verification, |
| 63 | * writing a proper implementation will usually want to take advantage |
| 64 | * of {@link java.security.cert.CertPathValidator |
| 65 | * CertPathValidator}. In general, it might be better to write a |
| 66 | * custom {@code KeyStore} implementation to pass to the {@code |
| 67 | * TrustManagerFactory} than to try and write a custom {@code |
| 68 | * X509TrustManager}. |
| 69 | * |
| 70 | * <h3>Providing an application specific X509KeyManager</h3> |
| 71 | * |
| 72 | * A custom {@code X509KeyManager} can be used to supply a client |
| 73 | * certificate and its associated private key to authenticate a |
| 74 | * connection to the server. The {@code X509KeyManager} can be created |
| 75 | * based on a {@code KeyStore} using a {@code KeyManagerFactory}. |
| 76 | * |
| 77 | * <p>For example, to supply client certificates from a {@code KeyStore}: |
| 78 | * <pre> {@code |
| 79 | * KeyStore keyStore = ...; |
| 80 | * KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509"); |
| 81 | * kmf.init(keyStore); |
| 82 | * |
| 83 | * SSLContext context = SSLContext.getInstance("TLS"); |
| 84 | * context.init(kmf.getKeyManagers(), null, null); |
| 85 | * |
| 86 | * URL url = new URL("https://www.example.com/"); |
| 87 | * HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); |
| 88 | * urlConnection.setSSLSocketFactory(context.getSocketFactory()); |
| 89 | * InputStream in = urlConnection.getInputStream(); |
| 90 | * }</pre> |
| 91 | * |
| 92 | * <p>A {@code X509KeyManager} can also be implemented directly. This |
| 93 | * can allow an application to return a certificate and private key |
| 94 | * from a non-{@code KeyStore} source or to specify its own logic for |
| 95 | * selecting a specific credential to use when many may be present in |
| 96 | * a single {@code KeyStore}. |
| 97 | * |
| 98 | * <h3>TLS Intolerance Support</h3> |
| 99 | * |
| 100 | * This class attempts to create secure connections using common TLS |
| 101 | * extensions and SSL deflate compression. Should that fail, the |
| 102 | * connection will be retried with SSLv3 only. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 103 | */ |
| 104 | public abstract class HttpsURLConnection extends HttpURLConnection { |
| 105 | |
| 106 | private static HostnameVerifier defaultHostnameVerifier = new DefaultHostnameVerifier(); |
| 107 | |
| 108 | private static SSLSocketFactory defaultSSLSocketFactory = (SSLSocketFactory) SSLSocketFactory |
| 109 | .getDefault(); |
| 110 | |
| 111 | /** |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 112 | * Sets the default hostname verifier to be used by new instances. |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 113 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 114 | * @param v |
| 115 | * the new default hostname verifier |
| 116 | * @throws IllegalArgumentException |
| 117 | * if the specified verifier is {@code null}. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 118 | */ |
| 119 | public static void setDefaultHostnameVerifier(HostnameVerifier v) { |
| 120 | if (v == null) { |
| 121 | throw new IllegalArgumentException("HostnameVerifier is null"); |
| 122 | } |
| 123 | defaultHostnameVerifier = v; |
| 124 | } |
| 125 | |
| 126 | /** |
| 127 | * Returns the default hostname verifier. |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 128 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 129 | * @return the default hostname verifier. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 130 | */ |
| 131 | public static HostnameVerifier getDefaultHostnameVerifier() { |
| 132 | return defaultHostnameVerifier; |
| 133 | } |
| 134 | |
| 135 | /** |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 136 | * Sets the default SSL socket factory to be used by new instances. |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 137 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 138 | * @param sf |
| 139 | * the new default SSL socket factory. |
| 140 | * @throws IllegalArgumentException |
| 141 | * if the specified socket factory is {@code null}. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 142 | */ |
| 143 | public static void setDefaultSSLSocketFactory(SSLSocketFactory sf) { |
| 144 | if (sf == null) { |
| 145 | throw new IllegalArgumentException("SSLSocketFactory is null"); |
| 146 | } |
| 147 | defaultSSLSocketFactory = sf; |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | * Returns the default SSL socket factory for new instances. |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 152 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 153 | * @return the default SSL socket factory for new instances. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 154 | */ |
| 155 | public static SSLSocketFactory getDefaultSSLSocketFactory() { |
| 156 | return defaultSSLSocketFactory; |
| 157 | } |
| 158 | |
| 159 | /** |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 160 | * The host name verifier used by this connection. It is initialized from |
| 161 | * the default hostname verifier |
| 162 | * {@link #setDefaultHostnameVerifier(HostnameVerifier)} or |
| 163 | * {@link #getDefaultHostnameVerifier()}. |
| 164 | */ |
| 165 | protected HostnameVerifier hostnameVerifier; |
| 166 | |
| 167 | private SSLSocketFactory sslSocketFactory; |
| 168 | |
| 169 | /** |
| 170 | * Creates a new {@code HttpsURLConnection} with the specified {@code URL}. |
| 171 | * |
| 172 | * @param url |
| 173 | * the {@code URL} to connect to. |
| 174 | */ |
| 175 | protected HttpsURLConnection(URL url) { |
| 176 | super(url); |
| 177 | hostnameVerifier = defaultHostnameVerifier; |
| 178 | sslSocketFactory = defaultSSLSocketFactory; |
| 179 | } |
| 180 | |
| 181 | /** |
| 182 | * Returns the name of the cipher suite negotiated during the SSL handshake. |
| 183 | * |
| 184 | * @return the name of the cipher suite negotiated during the SSL handshake. |
| 185 | * @throws IllegalStateException |
| 186 | * if no connection has been established yet. |
| 187 | */ |
| 188 | public abstract String getCipherSuite(); |
| 189 | |
| 190 | /** |
| 191 | * Returns the list of local certificates used during the handshake. These |
| 192 | * certificates were sent to the peer. |
| 193 | * |
| 194 | * @return Returns the list of certificates used during the handshake with |
| 195 | * the local identity certificate followed by CAs, or {@code null} |
| 196 | * if no certificates were used during the handshake. |
| 197 | * @throws IllegalStateException |
| 198 | * if no connection has been established yet. |
| 199 | */ |
| 200 | public abstract Certificate[] getLocalCertificates(); |
| 201 | |
| 202 | /** |
| 203 | * Return the list of certificates identifying the peer during the |
| 204 | * handshake. |
| 205 | * |
| 206 | * @return the list of certificates identifying the peer with the peer's |
| 207 | * identity certificate followed by CAs. |
| 208 | * @throws SSLPeerUnverifiedException |
| 209 | * if the identity of the peer has not been verified.. |
| 210 | * @throws IllegalStateException |
| 211 | * if no connection has been established yet. |
| 212 | */ |
| 213 | public abstract Certificate[] getServerCertificates() throws SSLPeerUnverifiedException; |
| 214 | |
| 215 | /** |
| 216 | * Returns the {@code Principal} identifying the peer. |
| 217 | * |
| 218 | * @return the {@code Principal} identifying the peer. |
| 219 | * @throws SSLPeerUnverifiedException |
| 220 | * if the identity of the peer has not been verified. |
| 221 | * @throws IllegalStateException |
| 222 | * if no connection has been established yet. |
| 223 | */ |
| 224 | public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { |
| 225 | Certificate[] certs = getServerCertificates(); |
| 226 | if (certs == null || certs.length == 0 || (!(certs[0] instanceof X509Certificate))) { |
| 227 | throw new SSLPeerUnverifiedException("No server's end-entity certificate"); |
| 228 | } |
| 229 | return ((X509Certificate) certs[0]).getSubjectX500Principal(); |
| 230 | } |
| 231 | |
| 232 | /** |
| 233 | * Returns the {@code Principal} used to identify the local host during the handshake. |
| 234 | * |
| 235 | * @return the {@code Principal} used to identify the local host during the handshake, or |
| 236 | * {@code null} if none was used. |
| 237 | * @throws IllegalStateException |
| 238 | * if no connection has been established yet. |
| 239 | */ |
| 240 | public Principal getLocalPrincipal() { |
| 241 | Certificate[] certs = getLocalCertificates(); |
| 242 | if (certs == null || certs.length == 0 || (!(certs[0] instanceof X509Certificate))) { |
| 243 | return null; |
| 244 | } |
| 245 | return ((X509Certificate) certs[0]).getSubjectX500Principal(); |
| 246 | } |
| 247 | |
| 248 | /** |
| 249 | * Sets the hostname verifier for this instance. |
| 250 | * |
| 251 | * @param v |
| 252 | * the hostname verifier for this instance. |
| 253 | * @throws IllegalArgumentException |
| 254 | * if the specified verifier is {@code null}. |
| 255 | */ |
| 256 | public void setHostnameVerifier(HostnameVerifier v) { |
| 257 | if (v == null) { |
| 258 | throw new IllegalArgumentException("HostnameVerifier is null"); |
| 259 | } |
| 260 | hostnameVerifier = v; |
| 261 | } |
| 262 | |
| 263 | /** |
| 264 | * Returns the hostname verifier used by this instance. |
| 265 | * |
| 266 | * @return the hostname verifier used by this instance. |
| 267 | */ |
| 268 | public HostnameVerifier getHostnameVerifier() { |
| 269 | return hostnameVerifier; |
| 270 | } |
| 271 | |
| 272 | /** |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 273 | * Sets the SSL socket factory for this instance. |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 274 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 275 | * @param sf |
| 276 | * the SSL socket factory to be used by this instance. |
| 277 | * @throws IllegalArgumentException |
| 278 | * if the specified socket factory is {@code null}. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 279 | */ |
| 280 | public void setSSLSocketFactory(SSLSocketFactory sf) { |
| 281 | if (sf == null) { |
| 282 | throw new IllegalArgumentException("SSLSocketFactory is null"); |
| 283 | } |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 284 | sslSocketFactory = sf; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 285 | } |
| 286 | |
| 287 | /** |
| 288 | * Returns the SSL socket factory used by this instance. |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 289 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 290 | * @return the SSL socket factory used by this instance. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 291 | */ |
| 292 | public SSLSocketFactory getSSLSocketFactory() { |
Jesse Wilson | f921579 | 2009-08-25 16:30:17 -0700 | [diff] [blame] | 293 | return sslSocketFactory; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 294 | } |
| 295 | |
| 296 | } |