diff options
author | Jan Nordqvist <jannq@google.com> | 2015-03-25 18:56:30 -0700 |
---|---|---|
committer | Vinit Deshpande <vinitd@google.com> | 2015-04-07 22:14:24 +0000 |
commit | 994932f1949316fe5520d6c690e6bd9b49b88ba6 (patch) | |
tree | 9285b2b3766d2e9979cb860e417f352b2ca3f681 /src | |
parent | 33c0a544f35937a5175e45dea1c71d37595c4d3f (diff) | |
download | android_packages_apps_CertInstaller-994932f1949316fe5520d6c690e6bd9b49b88ba6.tar.gz android_packages_apps_CertInstaller-994932f1949316fe5520d6c690e6bd9b49b88ba6.tar.bz2 android_packages_apps_CertInstaller-994932f1949316fe5520d6c690e6bd9b49b88ba6.zip |
Basic WiFi config installer app.
Change-Id: I12e26955f4057db7a1772eacfec6ce9fa58f4437
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/certinstaller/CertInstallerMain.java | 97 | ||||
-rw-r--r-- | src/com/android/certinstaller/WiFiInstaller.java | 228 |
2 files changed, 290 insertions, 35 deletions
diff --git a/src/com/android/certinstaller/CertInstallerMain.java b/src/com/android/certinstaller/CertInstallerMain.java index e184ae6..f95bb84 100644 --- a/src/com/android/certinstaller/CertInstallerMain.java +++ b/src/com/android/certinstaller/CertInstallerMain.java @@ -28,11 +28,14 @@ import android.security.KeyChain; import android.util.Log; import android.widget.Toast; -import libcore.io.IoUtils; -import libcore.io.Streams; - +import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import libcore.io.IoUtils; +import libcore.io.Streams; /** * The main class for installing certificates to the system keystore. It reacts @@ -46,19 +49,28 @@ public class CertInstallerMain extends PreferenceActivity { private static final String INSTALL_CERT_AS_USER_CLASS = ".InstallCertAsUser"; - private static final String[] ACCEPT_MIME_TYPES = { - "application/x-pkcs12", - "application/x-x509-ca-cert", - "application/x-x509-user-cert", - "application/x-x509-server-cert", - "application/x-pem-file", - "application/pkix-cert" - }; + public static final String WIFI_CONFIG = "wifi-config"; + public static final String WIFI_CONFIG_DATA = "wifi-config-data"; + public static final String WIFI_CONFIG_FILE = "wifi-config-file"; + + private static Map<String,String> MIME_MAPPINGS = new HashMap<>(); + + static { + MIME_MAPPINGS.put("application/x-x509-ca-cert", KeyChain.EXTRA_CERTIFICATE); + MIME_MAPPINGS.put("application/x-x509-user-cert", KeyChain.EXTRA_CERTIFICATE); + MIME_MAPPINGS.put("application/x-x509-server-cert", KeyChain.EXTRA_CERTIFICATE); + MIME_MAPPINGS.put("application/x-pem-file", KeyChain.EXTRA_CERTIFICATE); + MIME_MAPPINGS.put("application/pkix-cert", KeyChain.EXTRA_CERTIFICATE); + MIME_MAPPINGS.put("application/x-pkcs12", KeyChain.EXTRA_PKCS12); + MIME_MAPPINGS.put("application/x-wifi-config", WIFI_CONFIG); + } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Log.d("WFII", "Created!"); + setResult(RESULT_CANCELED); UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); @@ -96,7 +108,7 @@ public class CertInstallerMain extends PreferenceActivity { || bundle.containsKey(Credentials.EXTRA_INSTALL_AS_UID)))) { final Intent openIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT); openIntent.setType("*/*"); - openIntent.putExtra(Intent.EXTRA_MIME_TYPES, ACCEPT_MIME_TYPES); + openIntent.putExtra(Intent.EXTRA_MIME_TYPES, MIME_MAPPINGS.keySet().toArray()); openIntent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true); startActivityForResult(openIntent, REQUEST_OPEN_DOCUMENT); } else { @@ -114,38 +126,53 @@ public class CertInstallerMain extends PreferenceActivity { mimeType = getContentResolver().getType(uri); } - InputStream in = null; - try { - in = getContentResolver().openInputStream(uri); - - final byte[] raw = Streams.readFully(in); - startInstallActivity(mimeType, raw); + String target = MIME_MAPPINGS.get(mimeType); + if (target == null) { + throw new IllegalArgumentException("Unknown MIME type: " + mimeType); + } - } catch (IOException e) { - Log.e(TAG, "Failed to read certificate: " + e); - Toast.makeText(this, R.string.cert_read_error, Toast.LENGTH_LONG).show(); - } finally { - IoUtils.closeQuietly(in); + if (WIFI_CONFIG.equals(target)) { + startWifiInstallActivity(mimeType, uri); + } + else { + InputStream in = null; + try { + in = getContentResolver().openInputStream(uri); + + final byte[] raw = Streams.readFully(in); + startInstallActivity(target, raw); + + } catch (IOException e) { + Log.e(TAG, "Failed to read certificate: " + e); + Toast.makeText(this, R.string.cert_read_error, Toast.LENGTH_LONG).show(); + } finally { + IoUtils.closeQuietly(in); + } } } - private void startInstallActivity(String mimeType, byte[] value) { + private void startInstallActivity(String target, byte[] value) { Intent intent = new Intent(this, CertInstaller.class); - if ("application/x-pkcs12".equals(mimeType)) { - intent.putExtra(KeyChain.EXTRA_PKCS12, value); - } else if ("application/x-x509-ca-cert".equals(mimeType) - || "application/x-x509-user-cert".equals(mimeType) - || "application/x-x509-server-cert".equals(mimeType) - || "application/x-pem-file".equals(mimeType) - || "application/pkix-cert".equals(mimeType)) { - intent.putExtra(KeyChain.EXTRA_CERTIFICATE, value); - } else { - throw new IllegalArgumentException("Unknown MIME type: " + mimeType); - } + intent.putExtra(target, value); startActivityForResult(intent, REQUEST_INSTALL); } + private void startWifiInstallActivity(String mimeType, Uri uri) { + Intent intent = new Intent(this, WiFiInstaller.class); + try (BufferedInputStream in = + new BufferedInputStream(getContentResolver().openInputStream(uri))) { + byte[] data = Streams.readFully(in); + intent.putExtra(WIFI_CONFIG_FILE, uri.toString()); + intent.putExtra(WIFI_CONFIG_DATA, data); + intent.putExtra(WIFI_CONFIG, mimeType); + startActivityForResult(intent, REQUEST_INSTALL); + } catch (IOException e) { + Log.e(TAG, "Failed to read wifi config: " + e); + Toast.makeText(this, R.string.cert_read_error, Toast.LENGTH_LONG).show(); + } + } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_OPEN_DOCUMENT) { diff --git a/src/com/android/certinstaller/WiFiInstaller.java b/src/com/android/certinstaller/WiFiInstaller.java new file mode 100644 index 0000000..727134f --- /dev/null +++ b/src/com/android/certinstaller/WiFiInstaller.java @@ -0,0 +1,228 @@ +package com.android.certinstaller; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.Resources; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiEnterpriseConfig; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import java.security.PrivateKey; +import java.security.interfaces.RSAPrivateKey; +import java.util.Collection; + +public class WiFiInstaller extends Activity { + + @Override + protected void onCreate(Bundle savedStates) { + super.onCreate(savedStates); + + Bundle bundle = getIntent().getExtras(); + String uriString = bundle.getString(CertInstallerMain.WIFI_CONFIG_FILE); + String mimeType = bundle.getString(CertInstallerMain.WIFI_CONFIG); + byte[] data = bundle.getByteArray(CertInstallerMain.WIFI_CONFIG_DATA); + + Log.d("WFII", "WiFi data for " + CertInstallerMain.WIFI_CONFIG + ": " + + mimeType + " is " + (data != null ? data.length : "-")); + + WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); + WifiConfiguration wifiConfiguration = wifiManager.buildWifiConfig(uriString, mimeType, data); + createMainDialog(wifiManager, wifiConfiguration); + } + + private static String roamingConsortiumsToString(Collection<Long> ois) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (long oi : ois) { + if (first) { + first = false; + } else { + sb.append(", "); + } + if (Long.numberOfLeadingZeros(oi) > 40) { + sb.append(String.format("%06x", oi)); + } else { + sb.append(String.format("%010x", oi)); + } + } + return sb.toString(); + } + + private static String mapEAPMethod(WifiEnterpriseConfig config) { + switch (config.getEapMethod()) { + case WifiEnterpriseConfig.Eap.TTLS: + return "TTLS+" + mapInnerMethod(config.getPhase2Method()); + case WifiEnterpriseConfig.Eap.TLS: + return "TLS"; + case WifiEnterpriseConfig.Eap.SIM: + return "SIM"; + case WifiEnterpriseConfig.Eap.AKA: + return "AKA"; + case WifiEnterpriseConfig.Eap.AKA_PRIME: + return "AKA'"; + default: + return String.format("Unsupported method %d", config.getEapMethod()); + } + } + + private static String mapInnerMethod(int id) { + switch (id) { + case WifiEnterpriseConfig.Phase2.NONE: + return "none"; + case WifiEnterpriseConfig.Phase2.PAP: + return "PAP"; + case WifiEnterpriseConfig.Phase2.MSCHAP: + return "MS-CHAP"; + case WifiEnterpriseConfig.Phase2.MSCHAPV2: + return "MS-CHAPv2"; + case WifiEnterpriseConfig.Phase2.GTC: + return "GTC"; + default: + return String.format("Unsupported inner method %d", id); + } + } + + private void createMainDialog(final WifiManager wifiManager, final WifiConfiguration config) { + Resources res = getResources(); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + View layout = getLayoutInflater().inflate(R.layout.wifi_main_dialog, null); + builder.setView(layout); + + TextView text = (TextView) layout.findViewById(R.id.wifi_info); + text.setText(String.format("WiFi configuration from %s (%s)", + config.providerFriendlyName, config.FQDN)); + + Button detailButton = (Button) layout.findViewById(R.id.wifi_detail); + + detailButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + createDetailDialog(config); + } + }); + + builder.setTitle(res.getString(R.string.wifi_title)); + + builder.setPositiveButton(R.string.wifi_install_label, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Log.d("WFDL", "OK"); + wifiManager.addNetwork(config); + wifiManager.saveConfiguration(); + dialog.dismiss(); + finish(); + } + }); + + builder.setNegativeButton(R.string.wifi_cancel_label, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Log.d("WFDL", "Cancel"); + dialog.dismiss(); + finish(); + } + }); + + builder.create().show(); + } + + private void createDetailDialog(WifiConfiguration config) { + Resources res = getResources(); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + View layout = getLayoutInflater().inflate(R.layout.wifi_detail_dialog, null); + layout.setHorizontalScrollBarEnabled(true); + builder.setView(layout); + + TextView text = (TextView) layout.findViewById(R.id.wifi_detail_text); + text.setText(getDetailedInfo(res, config)); + + builder.setTitle(String.format(res.getString(R.string.wifi_detail_title), + config.providerFriendlyName)); + + builder.setPositiveButton(R.string.wifi_dismiss_label, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Log.d("WFDL", "detail dismiss"); + dialog.dismiss(); + } + }); + + builder.create().show(); + } + + private static String getDetailedInfo(Resources res, WifiConfiguration wifiConfiguration) { + if (wifiConfiguration == null) { + return res.getString(R.string.wifi_no_config); + } + + StringBuilder details = new StringBuilder(); + WifiEnterpriseConfig enterpriseConfig = wifiConfiguration.enterpriseConfig; + details.append(String.format(res.getString(R.string.wifi_config_text), + wifiConfiguration.providerFriendlyName, + wifiConfiguration.FQDN, + roamingConsortiumsToString(wifiConfiguration.roamingConsortiumIds), + enterpriseConfig.getRealm(), + mapEAPMethod(enterpriseConfig))); + + switch (enterpriseConfig.getEapMethod()) { + case WifiEnterpriseConfig.Eap.TTLS: + details.append(String.format(res.getString(R.string.wifi_ttls_config_text), enterpriseConfig.getIdentity())); + details.append("Password: ").append(enterpriseConfig.getPassword()).append('\n'); // !!! + if (enterpriseConfig.getCaCertificate() != null) { + details.append(String.format(res.getString(R.string.wifi_trust_config_text), enterpriseConfig.getCaCertificate())); + } + break; + case WifiEnterpriseConfig.Eap.TLS: + PrivateKey key = enterpriseConfig.getClientPrivateKey(); + String keyInfo; + if (key instanceof RSAPrivateKey) { + RSAPrivateKey rsaKey = (RSAPrivateKey) key; + int bits = rsaKey.getModulus().bitLength(); + keyInfo = "RSA " + (((bits + 7) / 8)*8) + " bits"; + } + else { + keyInfo = key.getAlgorithm(); + } + details.append(String.format(res.getString(R.string.wifi_tls_config_text), enterpriseConfig.getClientCertificate(), keyInfo)); + if (enterpriseConfig.getCaCertificate() != null) { + details.append(String.format(res.getString(R.string.wifi_trust_config_text), enterpriseConfig.getCaCertificate())); + } + break; + case WifiEnterpriseConfig.Eap.SIM: + case WifiEnterpriseConfig.Eap.AKA: + case WifiEnterpriseConfig.Eap.AKA_PRIME: + details.append(String.format(res.getString(R.string.wifi_sim_config_text), enterpriseConfig.getPlmn())); + break; + } + return details.toString(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onSaveInstanceState(Bundle outStates) { + super.onSaveInstanceState(outStates); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + finish(); + } +} |