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