PageRenderTime 78ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/emailcommon/src/com/android/emailcommon/utility/SSLSocketFactory.java

https://gitlab.com/Atomic-ROM/packages_apps_Email
Java | 405 lines | 209 code | 44 blank | 152 comment | 29 complexity | 75d954178f914526ddc25716477b0c99 MD5 | raw file
  1. /*
  2. * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java $
  3. * $Revision: 659194 $
  4. * $Date: 2008-05-22 11:33:47 -0700 (Thu, 22 May 2008) $
  5. *
  6. * ====================================================================
  7. * Licensed to the Apache Software Foundation (ASF) under one
  8. * or more contributor license agreements. See the NOTICE file
  9. * distributed with this work for additional information
  10. * regarding copyright ownership. The ASF licenses this file
  11. * to you under the Apache License, Version 2.0 (the
  12. * "License"); you may not use this file except in compliance
  13. * with the License. You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing,
  18. * software distributed under the License is distributed on an
  19. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  20. * KIND, either express or implied. See the License for the
  21. * specific language governing permissions and limitations
  22. * under the License.
  23. * ====================================================================
  24. *
  25. * This software consists of voluntary contributions made by many
  26. * individuals on behalf of the Apache Software Foundation. For more
  27. * information on the Apache Software Foundation, please see
  28. * <http://www.apache.org/>.
  29. *
  30. * This class was copied from org.apache.http.conn.ssl, because it didn't have a suitable
  31. * constructor.
  32. */
  33. package com.android.emailcommon.utility;
  34. import org.apache.http.conn.scheme.HostNameResolver;
  35. import org.apache.http.conn.scheme.LayeredSocketFactory;
  36. import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
  37. import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
  38. import org.apache.http.conn.ssl.StrictHostnameVerifier;
  39. import org.apache.http.conn.ssl.X509HostnameVerifier;
  40. import org.apache.http.params.HttpConnectionParams;
  41. import org.apache.http.params.HttpParams;
  42. import javax.net.ssl.HttpsURLConnection;
  43. import javax.net.ssl.KeyManager;
  44. import javax.net.ssl.KeyManagerFactory;
  45. import javax.net.ssl.SSLContext;
  46. import javax.net.ssl.SSLSocket;
  47. import javax.net.ssl.TrustManager;
  48. import javax.net.ssl.TrustManagerFactory;
  49. import java.io.IOException;
  50. import java.net.InetAddress;
  51. import java.net.InetSocketAddress;
  52. import java.net.Socket;
  53. import java.net.UnknownHostException;
  54. import java.security.KeyManagementException;
  55. import java.security.KeyStore;
  56. import java.security.KeyStoreException;
  57. import java.security.NoSuchAlgorithmException;
  58. import java.security.SecureRandom;
  59. import java.security.UnrecoverableKeyException;
  60. /**
  61. * Layered socket factory for TLS/SSL connections, based on JSSE.
  62. *.
  63. * <p>
  64. * SSLSocketFactory can be used to validate the identity of the HTTPS
  65. * server against a list of trusted certificates and to authenticate to
  66. * the HTTPS server using a private key.
  67. * </p>
  68. *
  69. * <p>
  70. * SSLSocketFactory will enable server authentication when supplied with
  71. * a {@link KeyStore truststore} file containg one or several trusted
  72. * certificates. The client secure socket will reject the connection during
  73. * the SSL session handshake if the target HTTPS server attempts to
  74. * authenticate itself with a non-trusted certificate.
  75. * </p>
  76. *
  77. * <p>
  78. * Use JDK keytool utility to import a trusted certificate and generate a truststore file:
  79. * <pre>
  80. * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
  81. * </pre>
  82. * </p>
  83. *
  84. * <p>
  85. * SSLSocketFactory will enable client authentication when supplied with
  86. * a {@link KeyStore keystore} file containg a private key/public certificate
  87. * pair. The client secure socket will use the private key to authenticate
  88. * itself to the target HTTPS server during the SSL session handshake if
  89. * requested to do so by the server.
  90. * The target HTTPS server will in its turn verify the certificate presented
  91. * by the client in order to establish client's authenticity
  92. * </p>
  93. *
  94. * <p>
  95. * Use the following sequence of actions to generate a keystore file
  96. * </p>
  97. * <ul>
  98. * <li>
  99. * <p>
  100. * Use JDK keytool utility to generate a new key
  101. * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
  102. * For simplicity use the same password for the key as that of the keystore
  103. * </p>
  104. * </li>
  105. * <li>
  106. * <p>
  107. * Issue a certificate signing request (CSR)
  108. * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
  109. * </p>
  110. * </li>
  111. * <li>
  112. * <p>
  113. * Send the certificate request to the trusted Certificate Authority for signature.
  114. * One may choose to act as her own CA and sign the certificate request using a PKI
  115. * tool, such as OpenSSL.
  116. * </p>
  117. * </li>
  118. * <li>
  119. * <p>
  120. * Import the trusted CA root certificate
  121. * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
  122. * </p>
  123. * </li>
  124. * <li>
  125. * <p>
  126. * Import the PKCS#7 file containg the complete certificate chain
  127. * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
  128. * </p>
  129. * </li>
  130. * <li>
  131. * <p>
  132. * Verify the content the resultant keystore file
  133. * <pre>keytool -list -v -keystore my.keystore</pre>
  134. * </p>
  135. * </li>
  136. * </ul>
  137. * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
  138. * @author Julius Davies
  139. */
  140. public class SSLSocketFactory implements LayeredSocketFactory {
  141. public static final String TLS = "TLS";
  142. public static final String SSL = "SSL";
  143. public static final String SSLV2 = "SSLv2";
  144. public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
  145. = new AllowAllHostnameVerifier();
  146. public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
  147. = new BrowserCompatHostnameVerifier();
  148. public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
  149. = new StrictHostnameVerifier();
  150. /**
  151. * The factory using the default JVM settings for secure connections.
  152. */
  153. private static final SSLSocketFactory DEFAULT_FACTORY = new SSLSocketFactory();
  154. /**
  155. * Gets an singleton instance of the SSLProtocolSocketFactory.
  156. * @return a SSLProtocolSocketFactory
  157. */
  158. public static SSLSocketFactory getSocketFactory() {
  159. return DEFAULT_FACTORY;
  160. }
  161. private final SSLContext sslcontext;
  162. private final javax.net.ssl.SSLSocketFactory socketfactory;
  163. private final HostNameResolver nameResolver;
  164. private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
  165. public SSLSocketFactory(
  166. String algorithm,
  167. final KeyStore keystore,
  168. final String keystorePassword,
  169. final KeyStore truststore,
  170. final SecureRandom random,
  171. final HostNameResolver nameResolver)
  172. throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
  173. {
  174. super();
  175. if (algorithm == null) {
  176. algorithm = TLS;
  177. }
  178. KeyManager[] keymanagers = null;
  179. if (keystore != null) {
  180. keymanagers = createKeyManagers(keystore, keystorePassword);
  181. }
  182. TrustManager[] trustmanagers = null;
  183. if (truststore != null) {
  184. trustmanagers = createTrustManagers(truststore);
  185. }
  186. sslcontext = SSLContext.getInstance(algorithm);
  187. sslcontext.init(keymanagers, trustmanagers, random);
  188. socketfactory = sslcontext.getSocketFactory();
  189. this.nameResolver = nameResolver;
  190. }
  191. public SSLSocketFactory(
  192. final KeyStore keystore,
  193. final String keystorePassword,
  194. final KeyStore truststore)
  195. throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
  196. {
  197. this(TLS, keystore, keystorePassword, truststore, null, null);
  198. }
  199. public SSLSocketFactory(final KeyStore keystore, final String keystorePassword)
  200. throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
  201. {
  202. this(TLS, keystore, keystorePassword, null, null, null);
  203. }
  204. public SSLSocketFactory(final KeyStore truststore)
  205. throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
  206. {
  207. this(TLS, null, null, truststore, null, null);
  208. }
  209. /**
  210. * Constructs an HttpClient SSLSocketFactory backed by the given JSSE
  211. * SSLSocketFactory.
  212. */
  213. public SSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory) {
  214. super();
  215. sslcontext = null;
  216. this.socketfactory = socketfactory;
  217. nameResolver = null;
  218. }
  219. /**
  220. * Creates the default SSL socket factory.
  221. * This constructor is used exclusively to instantiate the factory for
  222. * {@link #getSocketFactory getSocketFactory}.
  223. */
  224. private SSLSocketFactory() {
  225. super();
  226. sslcontext = null;
  227. socketfactory = HttpsURLConnection.getDefaultSSLSocketFactory();
  228. nameResolver = null;
  229. }
  230. private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password)
  231. throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
  232. if (keystore == null) {
  233. throw new IllegalArgumentException("Keystore may not be null");
  234. }
  235. KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
  236. KeyManagerFactory.getDefaultAlgorithm());
  237. kmfactory.init(keystore, password != null ? password.toCharArray(): null);
  238. return kmfactory.getKeyManagers();
  239. }
  240. private static TrustManager[] createTrustManagers(final KeyStore keystore)
  241. throws KeyStoreException, NoSuchAlgorithmException {
  242. if (keystore == null) {
  243. throw new IllegalArgumentException("Keystore may not be null");
  244. }
  245. TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
  246. TrustManagerFactory.getDefaultAlgorithm());
  247. tmfactory.init(keystore);
  248. return tmfactory.getTrustManagers();
  249. }
  250. // non-javadoc, see interface org.apache.http.conn.SocketFactory
  251. @Override
  252. public Socket createSocket()
  253. throws IOException {
  254. // the cast makes sure that the factory is working as expected
  255. return socketfactory.createSocket();
  256. }
  257. // non-javadoc, see interface org.apache.http.conn.SocketFactory
  258. @Override
  259. public Socket connectSocket(
  260. final Socket sock,
  261. final String host,
  262. final int port,
  263. final InetAddress localAddress,
  264. int localPort,
  265. final HttpParams params
  266. ) throws IOException {
  267. if (host == null) {
  268. throw new IllegalArgumentException("Target host may not be null.");
  269. }
  270. if (params == null) {
  271. throw new IllegalArgumentException("Parameters may not be null.");
  272. }
  273. SSLSocket sslsock = (SSLSocket)
  274. ((sock != null) ? sock : createSocket());
  275. if ((localAddress != null) || (localPort > 0)) {
  276. // we need to bind explicitly
  277. if (localPort < 0)
  278. localPort = 0; // indicates "any"
  279. InetSocketAddress isa =
  280. new InetSocketAddress(localAddress, localPort);
  281. sslsock.bind(isa);
  282. }
  283. int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
  284. int soTimeout = HttpConnectionParams.getSoTimeout(params);
  285. InetSocketAddress remoteAddress;
  286. if (nameResolver != null) {
  287. remoteAddress = new InetSocketAddress(nameResolver.resolve(host), port);
  288. } else {
  289. remoteAddress = new InetSocketAddress(host, port);
  290. }
  291. sslsock.connect(remoteAddress, connTimeout);
  292. sslsock.setSoTimeout(soTimeout);
  293. try {
  294. hostnameVerifier.verify(host, sslsock);
  295. // verifyHostName() didn't blowup - good!
  296. } catch (IOException iox) {
  297. // close the socket before re-throwing the exception
  298. try { sslsock.close(); } catch (Exception x) { /*ignore*/ }
  299. throw iox;
  300. }
  301. return sslsock;
  302. }
  303. /**
  304. * Checks whether a socket connection is secure.
  305. * This factory creates TLS/SSL socket connections
  306. * which, by default, are considered secure.
  307. * <br/>
  308. * Derived classes may override this method to perform
  309. * runtime checks, for example based on the cypher suite.
  310. *
  311. * @param sock the connected socket
  312. *
  313. * @return <code>true</code>
  314. *
  315. * @throws IllegalArgumentException if the argument is invalid
  316. */
  317. @Override
  318. public boolean isSecure(Socket sock)
  319. throws IllegalArgumentException {
  320. if (sock == null) {
  321. throw new IllegalArgumentException("Socket may not be null.");
  322. }
  323. // This instanceof check is in line with createSocket() above.
  324. if (!(sock instanceof SSLSocket)) {
  325. throw new IllegalArgumentException
  326. ("Socket not created by this factory.");
  327. }
  328. // This check is performed last since it calls the argument object.
  329. if (sock.isClosed()) {
  330. throw new IllegalArgumentException("Socket is closed.");
  331. }
  332. return true;
  333. } // isSecure
  334. // non-javadoc, see interface LayeredSocketFactory
  335. @Override
  336. public Socket createSocket(
  337. final Socket socket,
  338. final String host,
  339. final int port,
  340. final boolean autoClose
  341. ) throws IOException, UnknownHostException {
  342. SSLSocket sslSocket = (SSLSocket) socketfactory.createSocket(
  343. socket,
  344. host,
  345. port,
  346. autoClose
  347. );
  348. hostnameVerifier.verify(host, sslSocket);
  349. // verifyHostName() didn't blowup - good!
  350. return sslSocket;
  351. }
  352. public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) {
  353. if ( hostnameVerifier == null ) {
  354. throw new IllegalArgumentException("Hostname verifier may not be null");
  355. }
  356. this.hostnameVerifier = hostnameVerifier;
  357. }
  358. public X509HostnameVerifier getHostnameVerifier() {
  359. return hostnameVerifier;
  360. }
  361. }