AndroidNetworkLibrary.java revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.net; 6 7import android.content.ActivityNotFoundException; 8import android.content.Context; 9import android.content.Intent; 10import android.security.KeyChain; 11import android.util.Log; 12 13import org.chromium.base.CalledByNative; 14import org.chromium.base.CalledByNativeUnchecked; 15import org.chromium.net.CertVerifyResultAndroid; 16import org.chromium.net.CertificateMimeType; 17 18import java.net.Inet6Address; 19import java.net.InetAddress; 20import java.net.InterfaceAddress; 21import java.net.NetworkInterface; 22import java.net.SocketException; 23import java.net.URLConnection; 24import java.security.KeyStoreException; 25import java.security.NoSuchAlgorithmException; 26import java.security.cert.CertificateException; 27import java.util.Enumeration; 28import java.util.List; 29 30/** 31 * This class implements net utilities required by the net component. 32 */ 33class AndroidNetworkLibrary { 34 35 private static final String TAG = "AndroidNetworkLibrary"; 36 37 /** 38 * Stores the key pair through the CertInstaller activity. 39 * @param context: current application context. 40 * @param public_key: The public key bytes as DER-encoded SubjectPublicKeyInfo (X.509) 41 * @param private_key: The private key as DER-encoded PrivateKeyInfo (PKCS#8). 42 * @return: true on success, false on failure. 43 * 44 * Note that failure means that the function could not launch the CertInstaller 45 * activity. Whether the keys are valid or properly installed will be indicated 46 * by the CertInstaller UI itself. 47 */ 48 @CalledByNative 49 static public boolean storeKeyPair(Context context, byte[] public_key, byte[] private_key) { 50 // TODO(digit): Use KeyChain official extra values to pass the public and private 51 // keys when they're available. The "KEY" and "PKEY" hard-coded constants were taken 52 // from the platform sources, since there are no official KeyChain.EXTRA_XXX definitions 53 // for them. b/5859651 54 try { 55 Intent intent = KeyChain.createInstallIntent(); 56 intent.putExtra("PKEY", private_key); 57 intent.putExtra("KEY", public_key); 58 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 59 context.startActivity(intent); 60 return true; 61 } catch (ActivityNotFoundException e) { 62 Log.w(TAG, "could not store key pair: " + e); 63 } 64 return false; 65 } 66 67 /** 68 * Adds a cryptographic file (User certificate, a CA certificate or 69 * PKCS#12 keychain) through the system's CertInstaller activity. 70 * 71 * @param context: current application context. 72 * @param cert_type: cryptographic file type. E.g. CertificateMimeType.X509_USER_CERT 73 * @param data: certificate/keychain data bytes. 74 * @return true on success, false on failure. 75 * 76 * Note that failure only indicates that the function couldn't launch the 77 * CertInstaller activity, not that the certificate/keychain was properly 78 * installed to the keystore. 79 */ 80 @CalledByNative 81 static public boolean storeCertificate(Context context, int cert_type, byte[] data) { 82 try { 83 Intent intent = KeyChain.createInstallIntent(); 84 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 85 86 switch (cert_type) { 87 case CertificateMimeType.X509_USER_CERT: 88 case CertificateMimeType.X509_CA_CERT: 89 intent.putExtra(KeyChain.EXTRA_CERTIFICATE, data); 90 break; 91 92 case CertificateMimeType.PKCS12_ARCHIVE: 93 intent.putExtra(KeyChain.EXTRA_PKCS12, data); 94 break; 95 96 default: 97 Log.w(TAG, "invalid certificate type: " + cert_type); 98 return false; 99 } 100 context.startActivity(intent); 101 return true; 102 } catch (ActivityNotFoundException e) { 103 Log.w(TAG, "could not store crypto file: " + e); 104 } 105 return false; 106 } 107 108 /** 109 * @return the mime type (if any) that is associated with the file 110 * extension. Returns null if no corresponding mime type exists. 111 */ 112 @CalledByNative 113 static public String getMimeTypeFromExtension(String extension) { 114 return URLConnection.guessContentTypeFromName("foo." + extension); 115 } 116 117 /** 118 * @return true if it can determine that only loopback addresses are 119 * configured. i.e. if only 127.0.0.1 and ::1 are routable. Also 120 * returns false if it cannot determine this. 121 */ 122 @CalledByNative 123 static public boolean haveOnlyLoopbackAddresses() { 124 Enumeration<NetworkInterface> list = null; 125 try { 126 list = NetworkInterface.getNetworkInterfaces(); 127 if (list == null) return false; 128 } catch (Exception e) { 129 Log.w(TAG, "could not get network interfaces: " + e); 130 return false; 131 } 132 133 while (list.hasMoreElements()) { 134 NetworkInterface netIf = list.nextElement(); 135 try { 136 if (netIf.isUp() && !netIf.isLoopback()) return false; 137 } catch (SocketException e) { 138 continue; 139 } 140 } 141 return true; 142 } 143 144 /** 145 * @return the network interfaces list (if any) string. The items in 146 * the list string are delimited by a semicolon ";", each item 147 * is a network interface name and address pair and formatted 148 * as "name,address". e.g. 149 * eth0,10.0.0.2;eth0,fe80::5054:ff:fe12:3456 150 * represents a network list string which containts two items. 151 */ 152 @CalledByNative 153 static public String getNetworkList() { 154 Enumeration<NetworkInterface> list = null; 155 try { 156 list = NetworkInterface.getNetworkInterfaces(); 157 if (list == null) return ""; 158 } catch (SocketException e) { 159 Log.w(TAG, "Unable to get network interfaces: " + e); 160 return ""; 161 } 162 163 StringBuilder result = new StringBuilder(); 164 while (list.hasMoreElements()) { 165 NetworkInterface netIf = list.nextElement(); 166 try { 167 // Skip loopback interfaces, and ones which are down. 168 if (!netIf.isUp() || netIf.isLoopback()) 169 continue; 170 for (InterfaceAddress interfaceAddress : netIf.getInterfaceAddresses()) { 171 InetAddress address = interfaceAddress.getAddress(); 172 // Skip loopback addresses configured on non-loopback interfaces. 173 if (address.isLoopbackAddress()) 174 continue; 175 StringBuilder addressString = new StringBuilder(); 176 addressString.append(netIf.getName()); 177 addressString.append("\t"); 178 179 String ipAddress = address.getHostAddress(); 180 if (address instanceof Inet6Address && ipAddress.contains("%")) { 181 ipAddress = ipAddress.substring(0, ipAddress.lastIndexOf("%")); 182 } 183 addressString.append(ipAddress); 184 addressString.append("/"); 185 addressString.append(interfaceAddress.getNetworkPrefixLength()); 186 187 if (result.length() != 0) 188 result.append("\n"); 189 result.append(addressString.toString()); 190 } 191 } catch (SocketException e) { 192 continue; 193 } 194 } 195 return result.toString(); 196 } 197 198 /** 199 * Validate the server's certificate chain is trusted. 200 * 201 * @param certChain The ASN.1 DER encoded bytes for certificates. 202 * @param authType The key exchange algorithm name (e.g. RSA) 203 * @return Android certificate verification result code. 204 */ 205 @CalledByNative 206 public static int verifyServerCertificates(byte[][] certChain, String authType) { 207 try { 208 return X509Util.verifyServerCertificates(certChain, authType); 209 } catch (KeyStoreException e) { 210 return CertVerifyResultAndroid.VERIFY_FAILED; 211 } catch (NoSuchAlgorithmException e) { 212 return CertVerifyResultAndroid.VERIFY_FAILED; 213 } 214 } 215 216 /** 217 * Adds a test root certificate to the local trust store. 218 * @param rootCert DER encoded bytes of the certificate. 219 */ 220 @CalledByNativeUnchecked 221 public static void addTestRootCertificate(byte[] rootCert) throws CertificateException, 222 KeyStoreException, NoSuchAlgorithmException { 223 X509Util.addTestRootCertificate(rootCert); 224 } 225 226 /** 227 * Removes all test root certificates added by |addTestRootCertificate| calls from the local 228 * trust store. 229 */ 230 @CalledByNativeUnchecked 231 public static void clearTestRootCertificates() throws NoSuchAlgorithmException, 232 CertificateException, KeyStoreException { 233 X509Util.clearTestRootCertificates(); 234 } 235} 236