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
18package javax.net.ssl;
19
20import java.net.HttpURLConnection;
21import java.net.URL;
22import java.security.Principal;
23import java.security.cert.Certificate;
24import java.security.cert.X509Certificate;
25
26/**
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.
103 */
104public 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    /**
112     * Sets the default hostname verifier to be used by new instances.
113     *
114     * @param v
115     *            the new default hostname verifier
116     * @throws IllegalArgumentException
117     *             if the specified verifier is {@code null}.
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.
128     *
129     * @return the default hostname verifier.
130     */
131    public static HostnameVerifier getDefaultHostnameVerifier() {
132        return defaultHostnameVerifier;
133    }
134
135    /**
136     * Sets the default SSL socket factory to be used by new instances.
137     *
138     * @param sf
139     *            the new default SSL socket factory.
140     * @throws IllegalArgumentException
141     *             if the specified socket factory is {@code null}.
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.
152     *
153     * @return the default SSL socket factory for new instances.
154     */
155    public static SSLSocketFactory getDefaultSSLSocketFactory() {
156        return defaultSSLSocketFactory;
157    }
158
159    /**
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    /**
273     * Sets the SSL socket factory for this instance.
274     *
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}.
279     */
280    public void setSSLSocketFactory(SSLSocketFactory sf) {
281        if (sf == null) {
282            throw new IllegalArgumentException("SSLSocketFactory is null");
283        }
284        sslSocketFactory = sf;
285    }
286
287    /**
288     * Returns the SSL socket factory used by this instance.
289     *
290     * @return the SSL socket factory used by this instance.
291     */
292    public SSLSocketFactory getSSLSocketFactory() {
293        return sslSocketFactory;
294    }
295
296}
297