242 lines
9.5 KiB
Java
Executable File
242 lines
9.5 KiB
Java
Executable File
// Copyright 2012 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package org.chromium.net;
|
|
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.security.KeyChain;
|
|
import android.util.Log;
|
|
|
|
import org.chromium.base.CalledByNative;
|
|
import org.chromium.base.CalledByNativeUnchecked;
|
|
|
|
import java.net.Inet6Address;
|
|
import java.net.InetAddress;
|
|
import java.net.InterfaceAddress;
|
|
import java.net.NetworkInterface;
|
|
import java.net.SocketException;
|
|
import java.net.URLConnection;
|
|
import java.security.KeyStoreException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.cert.CertificateException;
|
|
import java.util.Enumeration;
|
|
|
|
/**
|
|
* This class implements net utilities required by the net component.
|
|
*/
|
|
class AndroidNetworkLibrary {
|
|
|
|
private static final String TAG = "AndroidNetworkLibrary";
|
|
|
|
/**
|
|
* Stores the key pair through the CertInstaller activity.
|
|
* @param context current application context.
|
|
* @param publicKey The public key bytes as DER-encoded SubjectPublicKeyInfo (X.509)
|
|
* @param privateKey The private key as DER-encoded PrivateKeyInfo (PKCS#8).
|
|
* @return: true on success, false on failure.
|
|
*
|
|
* Note that failure means that the function could not launch the CertInstaller
|
|
* activity. Whether the keys are valid or properly installed will be indicated
|
|
* by the CertInstaller UI itself.
|
|
*/
|
|
@CalledByNative
|
|
public static boolean storeKeyPair(Context context, byte[] publicKey, byte[] privateKey) {
|
|
// TODO(digit): Use KeyChain official extra values to pass the public and private
|
|
// keys when they're available. The "KEY" and "PKEY" hard-coded constants were taken
|
|
// from the platform sources, since there are no official KeyChain.EXTRA_XXX definitions
|
|
// for them. b/5859651
|
|
try {
|
|
Intent intent = KeyChain.createInstallIntent();
|
|
intent.putExtra("PKEY", privateKey);
|
|
intent.putExtra("KEY", publicKey);
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
context.startActivity(intent);
|
|
return true;
|
|
} catch (ActivityNotFoundException e) {
|
|
Log.w(TAG, "could not store key pair: " + e);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Adds a cryptographic file (User certificate, a CA certificate or
|
|
* PKCS#12 keychain) through the system's CertInstaller activity.
|
|
*
|
|
* @param context current application context.
|
|
* @param certType cryptographic file type. E.g. CertificateMimeType.X509_USER_CERT
|
|
* @param data certificate/keychain data bytes.
|
|
* @return true on success, false on failure.
|
|
*
|
|
* Note that failure only indicates that the function couldn't launch the
|
|
* CertInstaller activity, not that the certificate/keychain was properly
|
|
* installed to the keystore.
|
|
*/
|
|
@CalledByNative
|
|
public static boolean storeCertificate(Context context, int certType, byte[] data) {
|
|
try {
|
|
Intent intent = KeyChain.createInstallIntent();
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
switch (certType) {
|
|
case CertificateMimeType.X509_USER_CERT:
|
|
case CertificateMimeType.X509_CA_CERT:
|
|
intent.putExtra(KeyChain.EXTRA_CERTIFICATE, data);
|
|
break;
|
|
|
|
case CertificateMimeType.PKCS12_ARCHIVE:
|
|
intent.putExtra(KeyChain.EXTRA_PKCS12, data);
|
|
break;
|
|
|
|
default:
|
|
Log.w(TAG, "invalid certificate type: " + certType);
|
|
return false;
|
|
}
|
|
context.startActivity(intent);
|
|
return true;
|
|
} catch (ActivityNotFoundException e) {
|
|
Log.w(TAG, "could not store crypto file: " + e);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return the mime type (if any) that is associated with the file
|
|
* extension. Returns null if no corresponding mime type exists.
|
|
*/
|
|
@CalledByNative
|
|
public static String getMimeTypeFromExtension(String extension) {
|
|
return URLConnection.guessContentTypeFromName("foo." + extension);
|
|
}
|
|
|
|
/**
|
|
* @return true if it can determine that only loopback addresses are
|
|
* configured. i.e. if only 127.0.0.1 and ::1 are routable. Also
|
|
* returns false if it cannot determine this.
|
|
*/
|
|
@CalledByNative
|
|
public static boolean haveOnlyLoopbackAddresses() {
|
|
Enumeration<NetworkInterface> list = null;
|
|
try {
|
|
list = NetworkInterface.getNetworkInterfaces();
|
|
if (list == null) return false;
|
|
} catch (Exception e) {
|
|
Log.w(TAG, "could not get network interfaces: " + e);
|
|
return false;
|
|
}
|
|
|
|
while (list.hasMoreElements()) {
|
|
NetworkInterface netIf = list.nextElement();
|
|
try {
|
|
if (netIf.isUp() && !netIf.isLoopback()) return false;
|
|
} catch (SocketException e) {
|
|
continue;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @return the network interfaces list (if any) string. The items in
|
|
* the list string are delimited by a new line, each item
|
|
* is tab separated network interface name, address with network
|
|
* prefix length and network interface index.
|
|
* as "name\taddress/prefix\tindex". e.g.
|
|
* eth0\t10.0.0.2/8\t5\neth0\tfe80::5054:ff:fe12:3456/16\t5
|
|
* represents a network list string with two items.
|
|
*/
|
|
@CalledByNative
|
|
public static String getNetworkList() {
|
|
Enumeration<NetworkInterface> list = null;
|
|
try {
|
|
list = NetworkInterface.getNetworkInterfaces();
|
|
if (list == null) return "";
|
|
} catch (SocketException e) {
|
|
Log.w(TAG, "Unable to get network interfaces: " + e);
|
|
return "";
|
|
}
|
|
|
|
StringBuilder result = new StringBuilder();
|
|
while (list.hasMoreElements()) {
|
|
NetworkInterface netIf = list.nextElement();
|
|
try {
|
|
// Skip loopback interfaces, and ones which are down.
|
|
if (!netIf.isUp() || netIf.isLoopback())
|
|
continue;
|
|
for (InterfaceAddress interfaceAddress : netIf.getInterfaceAddresses()) {
|
|
InetAddress address = interfaceAddress.getAddress();
|
|
// Skip loopback addresses configured on non-loopback interfaces.
|
|
if (address.isLoopbackAddress())
|
|
continue;
|
|
StringBuilder addressString = new StringBuilder();
|
|
addressString.append(netIf.getName());
|
|
addressString.append("\t");
|
|
|
|
String ipAddress = address.getHostAddress();
|
|
if (address instanceof Inet6Address && ipAddress.contains("%")) {
|
|
ipAddress = ipAddress.substring(0, ipAddress.lastIndexOf("%"));
|
|
}
|
|
addressString.append(ipAddress);
|
|
addressString.append("/");
|
|
addressString.append(interfaceAddress.getNetworkPrefixLength());
|
|
addressString.append("\t");
|
|
|
|
// TODO(vitalybuka): use netIf.getIndex() when API level 19 is availible.
|
|
addressString.append("0");
|
|
|
|
if (result.length() != 0)
|
|
result.append("\n");
|
|
result.append(addressString.toString());
|
|
}
|
|
} catch (SocketException e) {
|
|
continue;
|
|
}
|
|
}
|
|
return result.toString();
|
|
}
|
|
|
|
/**
|
|
* Validate the server's certificate chain is trusted. Note that the caller
|
|
* must still verify the name matches that of the leaf certificate.
|
|
*
|
|
* @param certChain The ASN.1 DER encoded bytes for certificates.
|
|
* @param authType The key exchange algorithm name (e.g. RSA).
|
|
* @param host The hostname of the server.
|
|
* @return Android certificate verification result code.
|
|
*/
|
|
@CalledByNative
|
|
public static AndroidCertVerifyResult verifyServerCertificates(byte[][] certChain,
|
|
String authType,
|
|
String host) {
|
|
try {
|
|
return X509Util.verifyServerCertificates(certChain, authType, host);
|
|
} catch (KeyStoreException e) {
|
|
return new AndroidCertVerifyResult(CertVerifyStatusAndroid.VERIFY_FAILED);
|
|
} catch (NoSuchAlgorithmException e) {
|
|
return new AndroidCertVerifyResult(CertVerifyStatusAndroid.VERIFY_FAILED);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a test root certificate to the local trust store.
|
|
* @param rootCert DER encoded bytes of the certificate.
|
|
*/
|
|
@CalledByNativeUnchecked
|
|
public static void addTestRootCertificate(byte[] rootCert) throws CertificateException,
|
|
KeyStoreException, NoSuchAlgorithmException {
|
|
X509Util.addTestRootCertificate(rootCert);
|
|
}
|
|
|
|
/**
|
|
* Removes all test root certificates added by |addTestRootCertificate| calls from the local
|
|
* trust store.
|
|
*/
|
|
@CalledByNativeUnchecked
|
|
public static void clearTestRootCertificates() throws NoSuchAlgorithmException,
|
|
CertificateException, KeyStoreException {
|
|
X509Util.clearTestRootCertificates();
|
|
}
|
|
}
|