AndroidNetworkLibrary.java revision 5821806d5e7f356e8fa4b058a389a808ea183019
19085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org// Copyright (c) 2012 The Chromium Authors. All rights reserved. 29085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org// Use of this source code is governed by a BSD-style license that can be 39085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org// found in the LICENSE file. 45ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org 55ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.orgpackage org.chromium.net; 65ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org 75ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.orgimport android.content.ActivityNotFoundException; 89085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.content.Context; 99085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.content.Intent; 109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.security.KeyChain; 119085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.util.Log; 129085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 139085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport org.chromium.base.CalledByNative; 149085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport org.chromium.base.CalledByNativeUnchecked; 159085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 169085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.net.Inet6Address; 179085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.net.InetAddress; 189085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.net.NetworkInterface; 199085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.net.SocketException; 209085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.net.URLConnection; 219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.security.KeyStoreException; 229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.security.NoSuchAlgorithmException; 239085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.security.cert.CertificateException; 249085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport java.util.Enumeration; 259085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 269085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org/** 279085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * This class implements net utilities required by the net component. 289085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org */ 299085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgclass AndroidNetworkLibrary { 309085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 319085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org private static final String TAG = AndroidNetworkLibrary.class.getName(); 329085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 339085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org /** 349085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * Stores the key pair through the CertInstaller activity. 359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * @param context: current application context. 369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * @param public_key: The public key bytes as DER-encoded SubjectPublicKeyInfo (X.509) 379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * @param private_key: The private key as DER-encoded PrivateKeyInfo (PKCS#8). 389085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * @return: true on success, false on failure. 399085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * 4071affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org * Note that failure means that the function could not launch the CertInstaller 4171affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org * activity. Whether the keys are valid or properly installed will be indicated 429085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * by the CertInstaller UI itself. 43e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org */ 44e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org @CalledByNative 45e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org static public boolean storeKeyPair(Context context, byte[] public_key, byte[] private_key) { 46e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org // TODO(digit): Use KeyChain official extra values to pass the public and private 47e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org // keys when they're available. The "KEY" and "PKEY" hard-coded constants were taken 485aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org // from the platform sources, since there are no official KeyChain.EXTRA_XXX definitions 49e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org // for them. b/5859651 50e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org try { 51e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org Intent intent = KeyChain.createInstallIntent(); 52e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org intent.putExtra("PKEY", private_key); 53e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org intent.putExtra("KEY", public_key); 54e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 55e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org context.startActivity(intent); 569085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org return true; 579085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } catch (ActivityNotFoundException e) { 589085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org Log.w(TAG, "could not store key pair: " + e); 599085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } 609085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org return false; 619085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } 629085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 639085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org /** 649085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * @return the mime type (if any) that is associated with the file 659085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * extension. Returns null if no corresponding mime type exists. 669085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org */ 679085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org @CalledByNative 689085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org static public String getMimeTypeFromExtension(String extension) { 699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org return URLConnection.guessContentTypeFromName("foo." + extension); 709085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } 719085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 729085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org /** 739085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * @return true if it can determine that only loopback addresses are 749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * configured. i.e. if only 127.0.0.1 and ::1 are routable. Also 759085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * returns false if it cannot determine this. 769085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org */ 779085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org @CalledByNative 789085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org static public boolean haveOnlyLoopbackAddresses() { 79755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org Enumeration<NetworkInterface> list = null; 80eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org try { 81755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org list = NetworkInterface.getNetworkInterfaces(); 82755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org if (list == null) return false; 83755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org } catch (SocketException e) { 849085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org Log.w(TAG, "could not get network interfaces: " + e); 859085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org return false; 869085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } 879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 889085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org while (list.hasMoreElements()) { 899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org NetworkInterface netIf = list.nextElement(); 909085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org try { 919085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org if (netIf.isUp() && !netIf.isLoopback()) return false; 92eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org } catch (SocketException e) { 939085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org continue; 949085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } 955aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org } 965aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org return true; 975aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org } 985aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org 995aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org /** 1005aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * @return the network interfaces list (if any) string. The items in 1015aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * the list string are delimited by a semicolon ";", each item 1025aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * is a network interface name and address pair and formatted 1035aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * as "name,address". e.g. 1045aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * eth0,10.0.0.2;eth0,fe80::5054:ff:fe12:3456 1055aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * represents a network list string which containts two items. 106eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org */ 107eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org @CalledByNative 1089085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org static public String getNetworkList() { 1099085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org Enumeration<NetworkInterface> list = null; 1109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org try { 1119085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org list = NetworkInterface.getNetworkInterfaces(); 1129085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org if (list == null) return ""; 1139085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } catch (SocketException e) { 1149085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org Log.w(TAG, "Unable to get network interfaces: " + e); 1159085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org return ""; 1169085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } 1179085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 1189085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org StringBuilder result = new StringBuilder(); 1199085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org while (list.hasMoreElements()) { 1209085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org NetworkInterface netIf = list.nextElement(); 1219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org try { 1229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org // Skip loopback interfaces, and ones which are down. 1239085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org if (!netIf.isUp() || netIf.isLoopback()) 1249085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org continue; 1259085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org Enumeration<InetAddress> addressList = netIf.getInetAddresses(); 1269085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org while (addressList.hasMoreElements()) { 1279085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org InetAddress address = addressList.nextElement(); 1289085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org // Skip loopback addresses configured on non-loopback interfaces. 1295aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org if (address.isLoopbackAddress()) 1305aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org continue; 1315aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org StringBuilder addressString = new StringBuilder(); 1325aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org addressString.append(netIf.getName()); 1335aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org addressString.append(","); 1345aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org 1355aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org String ipAddress = address.getHostAddress(); 1365aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org if (address instanceof Inet6Address && ipAddress.contains("%")) { 1375aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org ipAddress = ipAddress.substring(0, ipAddress.lastIndexOf("%")); 1385aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org } 1395aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org addressString.append(ipAddress); 1405aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org 1415aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org if (result.length() != 0) 1425aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org result.append(";"); 1435aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org result.append(addressString.toString()); 1445aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org } 1455aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org } catch (SocketException e) { 1465aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org continue; 1475aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org } 1485aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org } 1495aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org return result.toString(); 1505aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org } 1515aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org 1525aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org /** 1535aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * Validate the server's certificate chain is trusted. 1545aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * 1555aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * @param certChain The ASN.1 DER encoded bytes for certificates. 1565aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * @param authType The key exchange algorithm name (e.g. RSA) 1575aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org * @return true if the server is trusted 1589085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * @throws CertificateException,KeyStoreException,NoSuchAlgorithmException 1599085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * on error initializing the TrustManager or reading the 1609085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * certChain 1619085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org */ 1629085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org @CalledByNativeUnchecked 1639085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org public static boolean verifyServerCertificates(byte[][] certChain, String authType) 1649085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org throws CertificateException, KeyStoreException, NoSuchAlgorithmException { 1659085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org return X509Util.verifyServerCertificates(certChain, authType); 1669085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org } 1679085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org 1689085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org} 1699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org