19b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff/* 29b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Copyright (C) 2013 The Android Open Source Project 39b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * 49b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License"); 59b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * you may not use this file except in compliance with the License. 69b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * You may obtain a copy of the License at 79b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * 89b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * http://www.apache.org/licenses/LICENSE-2.0 99b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * 109b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Unless required by applicable law or agreed to in writing, software 119b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS, 129b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * See the License for the specific language governing permissions and 149b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * limitations under the License. 159b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 169b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriffpackage android.net.wifi; 179b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 189b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriffimport android.os.Parcel; 199b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriffimport android.os.Parcelable; 208b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriffimport android.os.Process; 219b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriffimport android.security.Credentials; 22a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapndeimport android.security.KeyChain; 23b2c0ff64d8ff92dab53e969a44fa12427d145952Kenny Rootimport android.security.KeyStore; 249b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriffimport android.text.TextUtils; 25a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapndeimport android.util.Slog; 2626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 2726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.io.ByteArrayInputStream; 2826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.io.IOException; 2926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.KeyFactory; 3026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.NoSuchAlgorithmException; 3126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.PrivateKey; 3226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.cert.Certificate; 3326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.cert.CertificateEncodingException; 3426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.cert.CertificateException; 3526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.cert.CertificateFactory; 3626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.cert.X509Certificate; 3726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.spec.InvalidKeySpecException; 3826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriffimport java.security.spec.PKCS8EncodedKeySpec; 399b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriffimport java.util.HashMap; 409b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriffimport java.util.Map; 419b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 42fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff/** 43fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * Enterprise configuration details for Wi-Fi. Stores details about the EAP method 44fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * and any associated credentials. 45fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff */ 469b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriffpublic class WifiEnterpriseConfig implements Parcelable { 479b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String TAG = "WifiEnterpriseConfig"; 48a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde private static final boolean DBG = false; 499b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 509b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * In old configurations, the "private_key" field was used. However, newer 519b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * configurations use the key_id field with the engine_id set to "keystore". 529b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * If this field is found in the configuration, the migration code is 539b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * triggered. 549b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 559b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String OLD_PRIVATE_KEY_NAME = "private_key"; 569b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 579b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 589b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * String representing the keystore OpenSSL ENGINE's ID. 599b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 609b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String ENGINE_ID_KEYSTORE = "keystore"; 619b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 629b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 639b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * String representing the keystore URI used for wpa_supplicant. 649b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 659b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String KEYSTORE_URI = "keystore://"; 669b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 679b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 689b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * String to set the engine value to when it should be enabled. 699b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 709b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String ENGINE_ENABLE = "1"; 719b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 729b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 739b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * String to set the engine value to when it should be disabled. 749b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 759b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String ENGINE_DISABLE = "0"; 769b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 779b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE; 789b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE; 799b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 809b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String EAP_KEY = "eap"; 819b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String PHASE2_KEY = "phase2"; 829b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String IDENTITY_KEY = "identity"; 839b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String ANON_IDENTITY_KEY = "anonymous_identity"; 849b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String PASSWORD_KEY = "password"; 859b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String CLIENT_CERT_KEY = "client_cert"; 869b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String CA_CERT_KEY = "ca_cert"; 879b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String SUBJECT_MATCH_KEY = "subject_match"; 889b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String ENGINE_KEY = "engine"; 899b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String ENGINE_ID_KEY = "engine_id"; 909b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String PRIVATE_KEY_ID_KEY = "key_id"; 918d06e430307d07e3d51f381b4c7c89f7d9155133Partha N private static final String OPP_KEY_CACHING = "proactive_key_caching"; 929b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 939b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private HashMap<String, String> mFields = new HashMap<String, String>(); 9426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff private X509Certificate mCaCert; 9526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff private PrivateKey mClientPrivateKey; 9626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff private X509Certificate mClientCertificate; 97a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde private boolean mNeedsSoftwareKeystore = false; 989b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 999b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** This represents an empty value of an enterprise field. 1009b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * NULL is used at wpa_supplicant to indicate an empty value 1019b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 102e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff static final String EMPTY_VALUE = "NULL"; 1039b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 1049b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public WifiEnterpriseConfig() { 105e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff // Do not set defaults so that the enterprise fields that are not changed 106e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff // by API are not changed underneath 107e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff // This is essential because an app may not have all fields like password 108e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff // available. It allows modification of subset of fields. 109e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff 1109b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 1119b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 1129b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** Copy constructor */ 1139b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public WifiEnterpriseConfig(WifiEnterpriseConfig source) { 1149b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff for (String key : source.mFields.keySet()) { 1159b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(key, source.mFields.get(key)); 1169b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 1179b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 1189b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 1199b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff @Override 1209b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public int describeContents() { 1219b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return 0; 1229b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 1239b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 12486ee9640ee6d6bd9bb655af830eea5515400f25bIrfan Sheriff @Override 1259b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public void writeToParcel(Parcel dest, int flags) { 1269b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff dest.writeInt(mFields.size()); 1279b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff for (Map.Entry<String, String> entry : mFields.entrySet()) { 1289b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff dest.writeString(entry.getKey()); 1299b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff dest.writeString(entry.getValue()); 1309b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 13126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 13226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff writeCertificate(dest, mCaCert); 13326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 13426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (mClientPrivateKey != null) { 13526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String algorithm = mClientPrivateKey.getAlgorithm(); 13626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff byte[] userKeyBytes = mClientPrivateKey.getEncoded(); 13726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff dest.writeInt(userKeyBytes.length); 13826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff dest.writeByteArray(userKeyBytes); 13926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff dest.writeString(algorithm); 14026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } else { 14126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff dest.writeInt(0); 14226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 14326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 14426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff writeCertificate(dest, mClientCertificate); 14526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 14626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 14726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff private void writeCertificate(Parcel dest, X509Certificate cert) { 14826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (cert != null) { 14926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff try { 15026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff byte[] certBytes = cert.getEncoded(); 15126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff dest.writeInt(certBytes.length); 15226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff dest.writeByteArray(certBytes); 15326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } catch (CertificateEncodingException e) { 15426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff dest.writeInt(0); 15526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 15626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } else { 15726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff dest.writeInt(0); 15826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 1599b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 1609b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 1619b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final Creator<WifiEnterpriseConfig> CREATOR = 1629b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff new Creator<WifiEnterpriseConfig>() { 1639b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public WifiEnterpriseConfig createFromParcel(Parcel in) { 1649b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); 1659b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff int count = in.readInt(); 1669b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff for (int i = 0; i < count; i++) { 1679b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff String key = in.readString(); 1689b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff String value = in.readString(); 1699b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff enterpriseConfig.mFields.put(key, value); 1709b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 17126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 17226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff enterpriseConfig.mCaCert = readCertificate(in); 17326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 17426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff PrivateKey userKey = null; 17526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff int len = in.readInt(); 17626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (len > 0) { 17726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff try { 17826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff byte[] bytes = new byte[len]; 17926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff in.readByteArray(bytes); 18026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String algorithm = in.readString(); 18126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff KeyFactory keyFactory = KeyFactory.getInstance(algorithm); 18226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff userKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes)); 18326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } catch (NoSuchAlgorithmException e) { 18426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff userKey = null; 18526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } catch (InvalidKeySpecException e) { 18626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff userKey = null; 18726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 18826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 18926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 19026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff enterpriseConfig.mClientPrivateKey = userKey; 19126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff enterpriseConfig.mClientCertificate = readCertificate(in); 1929b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return enterpriseConfig; 1939b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 1949b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 19526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff private X509Certificate readCertificate(Parcel in) { 19626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff X509Certificate cert = null; 19726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff int len = in.readInt(); 19826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (len > 0) { 19926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff try { 20026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff byte[] bytes = new byte[len]; 20126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff in.readByteArray(bytes); 20226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff CertificateFactory cFactory = CertificateFactory.getInstance("X.509"); 20326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff cert = (X509Certificate) cFactory 20426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff .generateCertificate(new ByteArrayInputStream(bytes)); 20526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } catch (CertificateException e) { 20626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff cert = null; 20726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 20826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 20926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return cert; 21026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 21126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 2129b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public WifiEnterpriseConfig[] newArray(int size) { 2139b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return new WifiEnterpriseConfig[size]; 2149b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 2159b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff }; 2169b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 217fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** The Extensible Authentication Protocol method used */ 2189b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final class Eap { 219fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** No EAP method used. Represents an empty config */ 220e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff public static final int NONE = -1; 221fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** Protected EAP */ 2229b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int PEAP = 0; 223fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** EAP-Transport Layer Security */ 2249b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int TLS = 1; 225fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** EAP-Tunneled Transport Layer Security */ 2269b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int TTLS = 2; 227fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** EAP-Password */ 2289b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int PWD = 3; 2299b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** @hide */ 2309b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD" }; 23140843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff 23240843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff /** Prevent initialization */ 23340843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff private Eap() {} 2349b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 2359b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 236fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** The inner authentication method used */ 2379b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final class Phase2 { 2389b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int NONE = 0; 239fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** Password Authentication Protocol */ 2409b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int PAP = 1; 241fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** Microsoft Challenge Handshake Authentication Protocol */ 2429b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int MSCHAP = 2; 243fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** Microsoft Challenge Handshake Authentication Protocol v2 */ 2449b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int MSCHAPV2 = 3; 245fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff /** Generic Token Card */ 2469b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final int GTC = 4; 2479b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private static final String PREFIX = "auth="; 2489b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** @hide */ 2499b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP", "MSCHAPV2", "GTC" }; 25040843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff 25140843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff /** Prevent initialization */ 25240843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff private Phase2() {} 2539b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 2549b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 25526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff /** Internal use only */ 25626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff HashMap<String, String> getFields() { 2579b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return mFields; 2589b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 2599b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 26026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff /** Internal use only */ 26126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff static String[] getSupplicantKeys() { 262e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff return new String[] { EAP_KEY, PHASE2_KEY, IDENTITY_KEY, ANON_IDENTITY_KEY, PASSWORD_KEY, 263e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff CLIENT_CERT_KEY, CA_CERT_KEY, SUBJECT_MATCH_KEY, ENGINE_KEY, ENGINE_ID_KEY, 264e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff PRIVATE_KEY_ID_KEY }; 265e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff } 266e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff 2679b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 2689b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Set the EAP authentication method. 2699b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param eapMethod is one {@link Eap#PEAP}, {@link Eap#TLS}, {@link Eap#TTLS} or 2709b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * {@link Eap#PWD} 271fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * @throws IllegalArgumentException on an invalid eap method 2729b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 2739b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public void setEapMethod(int eapMethod) { 2749b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff switch (eapMethod) { 2759b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** Valid methods */ 2769b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Eap.PEAP: 2779b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Eap.PWD: 2789b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Eap.TLS: 2799b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Eap.TTLS: 2809b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(EAP_KEY, Eap.strings[eapMethod]); 2818d06e430307d07e3d51f381b4c7c89f7d9155133Partha N mFields.put(OPP_KEY_CACHING, "1"); 2829b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff break; 2839b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff default: 2849b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff throw new IllegalArgumentException("Unknown EAP method"); 2859b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 2869b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 2879b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 2889b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 2899b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Get the eap method. 2909b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return eap method configured 2919b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 2929b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public int getEapMethod() { 2939b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff String eapMethod = mFields.get(EAP_KEY); 294e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff return getStringIndex(Eap.strings, eapMethod, Eap.NONE); 2959b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 2969b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 2979b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 2989b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Set Phase 2 authentication method. Sets the inner authentication method to be used in 2999b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * phase 2 after setting up a secure channel 3009b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param phase2Method is the inner authentication method and can be one of {@link Phase2#NONE}, 3019b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * {@link Phase2#PAP}, {@link Phase2#MSCHAP}, {@link Phase2#MSCHAPV2}, 3029b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * {@link Phase2#GTC} 303fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * @throws IllegalArgumentException on an invalid phase2 method 3049b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * 3059b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 3069b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public void setPhase2Method(int phase2Method) { 3079b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff switch (phase2Method) { 3089b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Phase2.NONE: 3099b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(PHASE2_KEY, EMPTY_VALUE); 3109b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff break; 3119b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** Valid methods */ 3129b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Phase2.PAP: 3139b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Phase2.MSCHAP: 3149b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Phase2.MSCHAPV2: 3159b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff case Phase2.GTC: 3169b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(PHASE2_KEY, convertToQuotedString( 3179b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff Phase2.PREFIX + Phase2.strings[phase2Method])); 3189b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff break; 3199b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff default: 3209b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff throw new IllegalArgumentException("Unknown Phase 2 method"); 3219b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3229b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3239b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 3249b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 3259b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Get the phase 2 authentication method. 3269b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return a phase 2 method defined at {@link Phase2} 3279b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * */ 3289b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public int getPhase2Method() { 329e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff String phase2Method = removeDoubleQuotes(mFields.get(PHASE2_KEY)); 330e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff // Remove auth= prefix 331e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff if (phase2Method.startsWith(Phase2.PREFIX)) { 332e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff phase2Method = phase2Method.substring(Phase2.PREFIX.length()); 333e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff } 3349b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return getStringIndex(Phase2.strings, phase2Method, Phase2.NONE); 3359b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3369b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 3379b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 3389b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Set the identity 3399b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param identity 3409b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 3419b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public void setIdentity(String identity) { 3429b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff setFieldValue(IDENTITY_KEY, identity, ""); 3439b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3449b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 3459b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 3469b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Get the identity 3479b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return the identity 3489b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 3499b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public String getIdentity() { 3509b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return getFieldValue(IDENTITY_KEY, ""); 3519b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3529b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 3539b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 3549b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Set anonymous identity. This is used as the unencrypted identity with 3559b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * certain EAP types 3569b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param anonymousIdentity the anonymous identity 3579b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 3589b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public void setAnonymousIdentity(String anonymousIdentity) { 3599b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, ""); 3609b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3619b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 3629b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** Get the anonymous identity 3639b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return anonymous identity 3649b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 3659b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public String getAnonymousIdentity() { 3669b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return getFieldValue(ANON_IDENTITY_KEY, ""); 3679b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3689b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 3699b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 3709b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Set the password. 3719b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param password the password 3729b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 3739b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public void setPassword(String password) { 3749b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff setFieldValue(PASSWORD_KEY, password, ""); 3759b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3769b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 3779b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 37840843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * Get the password. 37940843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * 38040843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * Returns locally set password value. For networks fetched from 38140843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * framework, returns "*". 38240843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff */ 38340843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff public String getPassword() { 38440843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff return getFieldValue(PASSWORD_KEY, ""); 38540843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff } 38640843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff 38740843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff /** 3889b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Set CA certificate alias. 3899b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * 3909b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * <p> See the {@link android.security.KeyChain} for details on installing or choosing 3919b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * a certificate 3929b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * </p> 3939b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param alias identifies the certificate 39426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * @hide 3959b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 39626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff public void setCaCertificateAlias(String alias) { 3979b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff setFieldValue(CA_CERT_KEY, alias, CA_CERT_PREFIX); 3989b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 3999b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 4009b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 4019b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Get CA certificate alias 4029b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return alias to the CA certificate 40326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * @hide 4049b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 40526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff public String getCaCertificateAlias() { 4069b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); 4079b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 4089b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 4099b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 41026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * Specify a X.509 certificate that identifies the server. 41126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * 41226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * <p>A default name is automatically assigned to the certificate and used 413fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * with this configuration. The framework takes care of installing the 414fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * certificate when the config is saved and removing the certificate when 415fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * the config is removed. 416fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * 41726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * @param cert X.509 CA certificate 41826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * @throws IllegalArgumentException if not a CA certificate 41926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff */ 42026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff public void setCaCertificate(X509Certificate cert) { 4210b4732c2248fa2b92a44f045dfcadb3547076ef4Irfan Sheriff if (cert != null) { 4220b4732c2248fa2b92a44f045dfcadb3547076ef4Irfan Sheriff if (cert.getBasicConstraints() >= 0) { 4230b4732c2248fa2b92a44f045dfcadb3547076ef4Irfan Sheriff mCaCert = cert; 4240b4732c2248fa2b92a44f045dfcadb3547076ef4Irfan Sheriff } else { 4250b4732c2248fa2b92a44f045dfcadb3547076ef4Irfan Sheriff throw new IllegalArgumentException("Not a CA certificate"); 4260b4732c2248fa2b92a44f045dfcadb3547076ef4Irfan Sheriff } 42726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } else { 4280b4732c2248fa2b92a44f045dfcadb3547076ef4Irfan Sheriff mCaCert = null; 42926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 43026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 43126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 43226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff /** 43340843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * Get CA certificate 43440843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * 43540843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * @return X.509 CA certificate 43640843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff */ 43740843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff public X509Certificate getCaCertificate() { 43840843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff return mCaCert; 43940843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff } 44040843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff 44140843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff /** 4429b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Set Client certificate alias. 4439b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * 4449b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * <p> See the {@link android.security.KeyChain} for details on installing or choosing 4459b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * a certificate 4469b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * </p> 4479b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param alias identifies the certificate 44826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * @hide 4499b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 45026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff public void setClientCertificateAlias(String alias) { 4519b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX); 4529b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY); 4539b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff // Also, set engine parameters 4549b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff if (TextUtils.isEmpty(alias)) { 4559b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(ENGINE_KEY, ENGINE_DISABLE); 4569b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(ENGINE_ID_KEY, EMPTY_VALUE); 4579b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } else { 4589b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(ENGINE_KEY, ENGINE_ENABLE); 4599b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(ENGINE_ID_KEY, convertToQuotedString(ENGINE_ID_KEYSTORE)); 4609b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 4619b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 4629b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 4639b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 4649b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Get client certificate alias 4659b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return alias to the client certificate 46626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * @hide 4679b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 46826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff public String getClientCertificateAlias() { 4699b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); 4709b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 4719b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 4729b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 47326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * Specify a private key and client certificate for client authorization. 47426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * 47526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * <p>A default name is automatically assigned to the key entry and used 476fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * with this configuration. The framework takes care of installing the 477fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * key entry when the config is saved and removing the key entry when 478fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * the config is removed. 479fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff 48026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * @param privateKey 48126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff * @param clientCertificate 482fdc028383a01eaaa9bf93cb5d3ce50bd744eab52Irfan Sheriff * @throws IllegalArgumentException for an invalid key or certificate. 48326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff */ 48426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) { 48526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (clientCertificate != null) { 48626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (clientCertificate.getBasicConstraints() != -1) { 48726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff throw new IllegalArgumentException("Cannot be a CA certificate"); 48826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 48926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (privateKey == null) { 49026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff throw new IllegalArgumentException("Client cert without a private key"); 49126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 49226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (privateKey.getEncoded() == null) { 49326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff throw new IllegalArgumentException("Private key cannot be encoded"); 49426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 49526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 49626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 49726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff mClientPrivateKey = privateKey; 49826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff mClientCertificate = clientCertificate; 49926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 50026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 50140843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff /** 50240843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * Get client certificate 50340843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * 50440843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff * @return X.509 client certificate 50540843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff */ 50640843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff public X509Certificate getClientCertificate() { 50740843589c46164c90fde29ad1c58291f17d4d9e6Irfan Sheriff return mClientCertificate; 50826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 50926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 51026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff boolean needsKeyStore() { 51126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff // Has no keys to be installed 51226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (mClientCertificate == null && mCaCert == null) return false; 51326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return true; 51426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 51526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 516a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde static boolean isHardwareBackedKey(PrivateKey key) { 517a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); 518a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 519a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 520a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde static boolean hasHardwareBackedKey(Certificate certificate) { 521a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); 522a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 523a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 524a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde boolean needsSoftwareBackedKeyStore() { 525a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde return mNeedsSoftwareKeystore; 526a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 527a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 52826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff boolean installKeys(android.security.KeyStore keyStore, String name) { 52926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff boolean ret = true; 53026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String privKeyName = Credentials.USER_PRIVATE_KEY + name; 53126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String userCertName = Credentials.USER_CERTIFICATE + name; 53226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String caCertName = Credentials.CA_CERTIFICATE + name; 53326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (mClientCertificate != null) { 53426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff byte[] privKeyData = mClientPrivateKey.getEncoded(); 535a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (isHardwareBackedKey(mClientPrivateKey)) { 536a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // Hardware backed key store is secure enough to store keys un-encrypted, this 537a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // removes the need for user to punch a PIN to get access to these keys 538a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (DBG) Slog.d(TAG, "importing keys " + name + " in hardware backed " + 539a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde "store"); 540a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, 541a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde KeyStore.FLAG_NONE); 542a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } else { 543a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // Software backed key store is NOT secure enough to store keys un-encrypted. 544a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // Save keys encrypted so they are protected with user's PIN. User will 545a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // have to unlock phone before being able to use these keys and connect to 546a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // networks. 547a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (DBG) Slog.d(TAG, "importing keys " + name + " in software backed store"); 548a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, 549a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde KeyStore.FLAG_ENCRYPTED); 550a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde mNeedsSoftwareKeystore = true; 551a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 55226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (ret == false) { 55326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return ret; 55426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 55526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 55626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff ret = putCertInKeyStore(keyStore, userCertName, mClientCertificate); 55726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (ret == false) { 55826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff // Remove private key installed 5598b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.delKey(privKeyName, Process.WIFI_UID); 56026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return ret; 56126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 56226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 56326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 56426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (mCaCert != null) { 56526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff ret = putCertInKeyStore(keyStore, caCertName, mCaCert); 56626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (ret == false) { 56726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (mClientCertificate != null) { 56826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff // Remove client key+cert 5698b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.delKey(privKeyName, Process.WIFI_UID); 5708b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.delete(userCertName, Process.WIFI_UID); 57126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 57226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return ret; 57326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 57426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 57526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 57626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff // Set alias names 57726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (mClientCertificate != null) { 57826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff setClientCertificateAlias(name); 57926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff mClientPrivateKey = null; 58026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff mClientCertificate = null; 58126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 58226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 58326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (mCaCert != null) { 58426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff setCaCertificateAlias(name); 58526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff mCaCert = null; 58626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 58726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 58826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return ret; 58926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 59026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 59126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff private boolean putCertInKeyStore(android.security.KeyStore keyStore, String name, 59226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff Certificate cert) { 59326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff try { 59426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff byte[] certData = Credentials.convertToPem(cert); 595a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (DBG) Slog.d(TAG, "putting certificate " + name + " in keystore"); 596a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde return keyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); 597a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 59826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } catch (IOException e1) { 59926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return false; 60026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } catch (CertificateException e2) { 60126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return false; 60226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 60326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 60426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 605b2c0ff64d8ff92dab53e969a44fa12427d145952Kenny Root void removeKeys(KeyStore keyStore) { 60626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); 60726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff // a valid client certificate is configured 60826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (!TextUtils.isEmpty(client)) { 609a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (DBG) Slog.d(TAG, "removing client private key and user cert"); 6108b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 6118b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 61226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 61326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 61426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); 61526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff // a valid ca certificate is configured 61626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (!TextUtils.isEmpty(ca)) { 617a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (DBG) Slog.d(TAG, "removing CA cert"); 6188b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 61926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 62026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 62126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 62226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff /** 6239b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Set subject match. This is the substring to be matched against the subject of the 6249b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * authentication server certificate. 6259b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param subjectMatch substring to be matched 6269b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 6279b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public void setSubjectMatch(String subjectMatch) { 6289b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff setFieldValue(SUBJECT_MATCH_KEY, subjectMatch, ""); 6299b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 6309b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 6319b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** 6329b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * Get subject match 6339b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return the subject match string 6349b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 6359b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public String getSubjectMatch() { 6369b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return getFieldValue(SUBJECT_MATCH_KEY, ""); 6379b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 6389b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 63926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */ 64026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String getKeyId(WifiEnterpriseConfig current) { 64126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String eap = mFields.get(EAP_KEY); 64226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff String phase2 = mFields.get(PHASE2_KEY); 64326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 64426d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff // If either eap or phase2 are not initialized, use current config details 64526d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (TextUtils.isEmpty((eap))) { 64626d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff eap = current.mFields.get(EAP_KEY); 64726d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 64826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (TextUtils.isEmpty(phase2)) { 64926d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff phase2 = current.mFields.get(PHASE2_KEY); 65026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 65126d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff return eap + "_" + phase2; 65226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff } 65326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff 6549b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** Migrates the old style TLS config to the new config style. This should only be used 6559b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * when restoring an old wpa_supplicant.conf or upgrading from a previous 6569b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * platform version. 6579b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return true if the config was updated 6589b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @hide 6599b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 66026d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff boolean migrateOldEapTlsNative(WifiNative wifiNative, int netId) { 6619b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff String oldPrivateKey = wifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); 6629b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /* 6639b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * If the old configuration value is not present, then there is nothing 6649b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * to do. 6659b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 6669b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff if (TextUtils.isEmpty(oldPrivateKey)) { 6679b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return false; 6689b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } else { 6699b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff // Also ignore it if it's empty quotes. 6709b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff oldPrivateKey = removeDoubleQuotes(oldPrivateKey); 6719b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff if (TextUtils.isEmpty(oldPrivateKey)) { 6729b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return false; 6739b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 6749b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 6759b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 6769b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(ENGINE_KEY, ENGINE_ENABLE); 6779b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(ENGINE_ID_KEY, convertToQuotedString(ENGINE_ID_KEYSTORE)); 6789b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 6799b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /* 6809b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * The old key started with the keystore:// URI prefix, but we don't 6819b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * need that anymore. Trim it off if it exists. 6829b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 6839b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff final String keyName; 6849b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff if (oldPrivateKey.startsWith(KEYSTORE_URI)) { 6859b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff keyName = new String(oldPrivateKey.substring(KEYSTORE_URI.length())); 6869b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } else { 6879b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff keyName = oldPrivateKey; 6889b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 6899b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(PRIVATE_KEY_ID_KEY, convertToQuotedString(keyName)); 6909b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 6919b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff wifiNative.setNetworkVariable(netId, ENGINE_KEY, mFields.get(ENGINE_KEY)); 6929b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff wifiNative.setNetworkVariable(netId, ENGINE_ID_KEY, mFields.get(ENGINE_ID_KEY)); 6939b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff wifiNative.setNetworkVariable(netId, PRIVATE_KEY_ID_KEY, mFields.get(PRIVATE_KEY_ID_KEY)); 6949b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff // Remove old private_key string so we don't run this again. 6959b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff wifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); 6969b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return true; 6979b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 6989b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 6998b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff /** Migrate certs from global pool to wifi UID if not already done */ 7008b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff void migrateCerts(android.security.KeyStore keyStore) { 7018b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); 7028b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff // a valid client certificate is configured 7038b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff if (!TextUtils.isEmpty(client)) { 7048b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff if (!keyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { 7058b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, 7068b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 7078b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, 7088b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 7098b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff } 7108b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff } 7118b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff 7128b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); 7138b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff // a valid ca certificate is configured 7148b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff if (!TextUtils.isEmpty(ca)) { 7158b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff if (!keyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { 7168b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff keyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, 7178b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 7188b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff } 7198b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff } 7208b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff } 7218b643c13f97c0f304a45039b9d1fe6900940499eIrfan Sheriff 722a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde void initializeSoftwareKeystoreFlag(android.security.KeyStore keyStore) { 723a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); 724a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (!TextUtils.isEmpty(client)) { 725a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // a valid client certificate is configured 726a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 727a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // BUGBUG: keyStore.get() never returns certBytes; because it is not 728a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // taking WIFI_UID as a parameter. It always looks for certificate 729a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 730a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // all certificates need software keystore until we get the get() API 731a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde // fixed. 732a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 733a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde mNeedsSoftwareKeystore = true; 734a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 735a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde /* 736a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde try { 737a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 738a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 739a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde .USER_CERTIFICATE + client); 740a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 741a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde CertificateFactory factory = CertificateFactory.getInstance("X.509"); 742a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (factory == null) { 743a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde Slog.e(TAG, "Error getting certificate factory"); 744a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde return; 745a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 746a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 747a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 748a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (certBytes != null) { 749a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde Certificate cert = (X509Certificate) factory.generateCertificate( 750a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde new ByteArrayInputStream(certBytes)); 751a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 752a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (cert != null) { 753a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 754a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 755a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 756a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde .USER_CERTIFICATE + client); 757a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 758a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde "does not need" ) + " software key store"); 759a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } else { 760a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde Slog.d(TAG, "could not generate certificate"); 761a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 762a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } else { 763a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde Slog.e(TAG, "Could not load client certificate " + Credentials 764a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde .USER_CERTIFICATE + client); 765a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde mNeedsSoftwareKeystore = true; 766a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 767a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 768a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } catch(CertificateException e) { 769a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde Slog.e(TAG, "Could not read certificates"); 770a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde mCaCert = null; 771a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde mClientCertificate = null; 772a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 773a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde */ 774a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 775a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde } 776a3038b2b311cd07d851c404ccc5df2f4e07bcfd8Vinit Deshapnde 7779b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private String removeDoubleQuotes(String string) { 7780b4732c2248fa2b92a44f045dfcadb3547076ef4Irfan Sheriff if (TextUtils.isEmpty(string)) return ""; 7799b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff int length = string.length(); 7809b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff if ((length > 1) && (string.charAt(0) == '"') 7819b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff && (string.charAt(length - 1) == '"')) { 7829b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return string.substring(1, length - 1); 7839b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 7849b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return string; 7859b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 7869b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 7879b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private String convertToQuotedString(String string) { 7889b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return "\"" + string + "\""; 7899b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 7909b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 7919b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** Returns the index at which the toBeFound string is found in the array. 7929b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param arr array of strings 7939b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param toBeFound string to be found 7949b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param defaultIndex default index to be returned when string is not found 7959b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return the index into array 7969b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 7979b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private int getStringIndex(String arr[], String toBeFound, int defaultIndex) { 79826d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (TextUtils.isEmpty(toBeFound)) return defaultIndex; 7999b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff for (int i = 0; i < arr.length; i++) { 800e095675c872f40f630aa3f9189eb5c02f3cfee6dIrfan Sheriff if (toBeFound.equals(arr[i])) return i; 8019b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 8029b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return defaultIndex; 8039b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 8049b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 8059b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** Returns the field value for the key. 8069b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param key into the hash 8079b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param prefix is the prefix that the value may have 8089b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @return value 8099b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 8109b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private String getFieldValue(String key, String prefix) { 8119b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff String value = mFields.get(key); 81226d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff // Uninitialized or known to be empty after reading from supplicant 81326d0076f0dbb021c4e5cc1b37b632b2223fd9278Irfan Sheriff if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return ""; 814dda5a7152fd6e5933503aba8e8badbbba0631839Vinit Deshapnde 815dda5a7152fd6e5933503aba8e8badbbba0631839Vinit Deshapnde value = removeDoubleQuotes(value); 816dda5a7152fd6e5933503aba8e8badbbba0631839Vinit Deshapnde if (value.startsWith(prefix)) { 817dda5a7152fd6e5933503aba8e8badbbba0631839Vinit Deshapnde return value.substring(prefix.length()); 818dda5a7152fd6e5933503aba8e8badbbba0631839Vinit Deshapnde } else { 819dda5a7152fd6e5933503aba8e8badbbba0631839Vinit Deshapnde return value; 820dda5a7152fd6e5933503aba8e8badbbba0631839Vinit Deshapnde } 8219b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 8229b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 8239b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff /** Set a value with an optional prefix at key 8249b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param key into the hash 8259b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param value to be set 8269b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff * @param prefix an optional value to be prefixed to actual value 8279b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff */ 8289b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff private void setFieldValue(String key, String value, String prefix) { 8299b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff if (TextUtils.isEmpty(value)) { 8309b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(key, EMPTY_VALUE); 8319b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } else { 8329b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff mFields.put(key, convertToQuotedString(prefix + value)); 8339b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 8349b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 8359b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff 8369b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff @Override 8379b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff public String toString() { 8389b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff StringBuffer sb = new StringBuffer(); 8399b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff for (String key : mFields.keySet()) { 8409b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff sb.append(key).append(" ").append(mFields.get(key)).append("\n"); 8419b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 8429b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff return sb.toString(); 8439b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff } 8449b81319002634cf7118055f7aafaa26c27d4e5e8Irfan Sheriff} 845