13c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills/* 23c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Copyright (C) 2016 The Android Open Source Project 33c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * 43c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Licensed under the Apache License, Version 2.0 (the "License"); 53c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * you may not use this file except in compliance with the License. 63c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * You may obtain a copy of the License at 73c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * 83c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * http://www.apache.org/licenses/LICENSE-2.0 93c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * 103c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Unless required by applicable law or agreed to in writing, software 113c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * distributed under the License is distributed on an "AS IS" BASIS, 123c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * See the License for the specific language governing permissions and 143c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * limitations under the License. 153c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */ 163c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 173c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willspackage com.android.server.wifi.util; 183c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 193c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willsimport android.net.wifi.WifiConfiguration; 203c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willsimport android.net.wifi.WifiEnterpriseConfig; 213c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willsimport android.telephony.TelephonyManager; 22259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Willsimport android.util.Base64; 23259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Willsimport android.util.Log; 243c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 25b8b3fb8228a1f90106bad8c59ce006b81ef7921cRoshan Piusimport com.android.server.wifi.WifiNative; 26b8b3fb8228a1f90106bad8c59ce006b81ef7921cRoshan Pius 273c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills/** 283c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Utilities for the Wifi Service to interact with telephony. 293c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */ 303c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willspublic class TelephonyUtil { 31259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public static final String TAG = "TelephonyUtil"; 323c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 333c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills /** 348757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * Get the identity for the current SIM or null if the SIM is not available 358757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * 368757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @param tm TelephonyManager instance 378757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @param config WifiConfiguration that indicates what sort of authentication is necessary 388757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @return String with the identity or none if the SIM is not available or config is invalid 393c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */ 408757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart public static String getSimIdentity(TelephonyManager tm, WifiConfiguration config) { 41259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (tm == null) { 42259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "No valid TelephonyManager"); 433c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills return null; 443c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 45259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String imsi = tm.getSubscriberId(); 46259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String mccMnc = ""; 47259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 48259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) { 49259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills mccMnc = tm.getSimOperator(); 50259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 51259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 528757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart return buildIdentity(getSimMethodForConfig(config), imsi, mccMnc); 533c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 543c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 553c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills /** 563c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * create Permanent Identity base on IMSI, 573c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * 583c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * rfc4186 & rfc4187: 593c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * identity = usernam@realm 603c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * with username = prefix | IMSI 613c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003) 623c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */ 633c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills private static String buildIdentity(int eapMethod, String imsi, String mccMnc) { 643c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills if (imsi == null || imsi.isEmpty()) { 658757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart Log.e(TAG, "No IMSI or IMSI is null"); 663c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills return null; 673c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 683c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 693c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills String prefix; 703c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills if (eapMethod == WifiEnterpriseConfig.Eap.SIM) { 713c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills prefix = "1"; 723c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } else if (eapMethod == WifiEnterpriseConfig.Eap.AKA) { 733c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills prefix = "0"; 743c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME) { 753c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills prefix = "6"; 768757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart } else { 778757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart Log.e(TAG, "Invalid EAP method"); 783c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills return null; 793c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 803c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 813c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills /* extract mcc & mnc from mccMnc */ 823c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills String mcc; 833c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills String mnc; 843c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills if (mccMnc != null && !mccMnc.isEmpty()) { 853c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills mcc = mccMnc.substring(0, 3); 863c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills mnc = mccMnc.substring(3); 873c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills if (mnc.length() == 2) { 883c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills mnc = "0" + mnc; 893c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 903c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } else { 913c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills // extract mcc & mnc from IMSI, assume mnc size is 3 923c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills mcc = imsi.substring(0, 3); 933c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills mnc = imsi.substring(3, 6); 943c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 953c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 963c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org"; 973c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 983c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 993c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills /** 1008757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * Return the associated SIM method for the configuration. 1013c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * 1028757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @param config WifiConfiguration corresponding to the network. 1038757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @return the outer EAP method associated with this SIM configuration. 1043c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */ 1058757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart private static int getSimMethodForConfig(WifiConfiguration config) { 1063c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills if (config == null || config.enterpriseConfig == null) { 1078757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart return WifiEnterpriseConfig.Eap.NONE; 1088757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart } 1098757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart int eapMethod = config.enterpriseConfig.getEapMethod(); 1108757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart if (eapMethod == WifiEnterpriseConfig.Eap.PEAP) { 1118757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart // Translate known inner eap methods into an equivalent outer eap method. 1128757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart switch (config.enterpriseConfig.getPhase2Method()) { 1138757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart case WifiEnterpriseConfig.Phase2.SIM: 1148757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart eapMethod = WifiEnterpriseConfig.Eap.SIM; 1158757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart break; 1168757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart case WifiEnterpriseConfig.Phase2.AKA: 1178757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart eapMethod = WifiEnterpriseConfig.Eap.AKA; 1188757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart break; 1198757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart case WifiEnterpriseConfig.Phase2.AKA_PRIME: 1208757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart eapMethod = WifiEnterpriseConfig.Eap.AKA_PRIME; 1218757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart break; 1228757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart } 1233c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 1243c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 1258757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart return isSimEapMethod(eapMethod) ? eapMethod : WifiEnterpriseConfig.Eap.NONE; 1268757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart } 1278757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart 1288757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart /** 1298757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * Checks if the network is a SIM config. 1308757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * 1318757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @param config Config corresponding to the network. 1328757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @return true if it is a SIM config, false otherwise. 1338757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart */ 1348757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart public static boolean isSimConfig(WifiConfiguration config) { 1358757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart return getSimMethodForConfig(config) != WifiEnterpriseConfig.Eap.NONE; 1363c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 1373c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills 1383c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills /** 1398757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * Checks if the EAP outer method is SIM related. 1403c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * 1418757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @param eapMethod WifiEnterpriseConfig Eap method. 1428757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart * @return true if this EAP outer method is SIM-related, false otherwise. 1433c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */ 1443c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills public static boolean isSimEapMethod(int eapMethod) { 1453c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills return eapMethod == WifiEnterpriseConfig.Eap.SIM 1463c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills || eapMethod == WifiEnterpriseConfig.Eap.AKA 1473c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME; 1483c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills } 149259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 150259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills // TODO replace some of this code with Byte.parseByte 151259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills private static int parseHex(char ch) { 152259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if ('0' <= ch && ch <= '9') { 153259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return ch - '0'; 154259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else if ('a' <= ch && ch <= 'f') { 155259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return ch - 'a' + 10; 156259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else if ('A' <= ch && ch <= 'F') { 157259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return ch - 'A' + 10; 158259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else { 159259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills throw new NumberFormatException("" + ch + " is not a valid hex digit"); 160259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 161259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 162259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 163259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills private static byte[] parseHex(String hex) { 164259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills /* This only works for good input; don't throw bad data at it */ 165259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (hex == null) { 166259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return new byte[0]; 167259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 168259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 169259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (hex.length() % 2 != 0) { 170259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills throw new NumberFormatException(hex + " is not a valid hex string"); 171259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 172259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 173259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte[] result = new byte[(hex.length()) / 2 + 1]; 174259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills result[0] = (byte) ((hex.length()) / 2); 175259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills for (int i = 0, j = 1; i < hex.length(); i += 2, j++) { 176259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i + 1)); 177259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte b = (byte) (val & 0xFF); 178259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills result[j] = b; 179259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 180259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 181259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return result; 182259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 183259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 184259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills private static String makeHex(byte[] bytes) { 185259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills StringBuilder sb = new StringBuilder(); 186259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills for (byte b : bytes) { 187259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills sb.append(String.format("%02x", b)); 188259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 189259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return sb.toString(); 190259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 191259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 192259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills private static String makeHex(byte[] bytes, int from, int len) { 193259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills StringBuilder sb = new StringBuilder(); 194259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills for (int i = 0; i < len; i++) { 195259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills sb.append(String.format("%02x", bytes[from + i])); 196259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 197259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return sb.toString(); 198259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 199259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 200259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills private static byte[] concatHex(byte[] array1, byte[] array2) { 201259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 202259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int len = array1.length + array2.length; 203259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 204259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte[] result = new byte[len]; 205259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 206259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int index = 0; 207259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (array1.length != 0) { 208259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills for (byte b : array1) { 209259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills result[index] = b; 210259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills index++; 211259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 212259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 213259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 214259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (array2.length != 0) { 215259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills for (byte b : array2) { 216259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills result[index] = b; 217259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills index++; 218259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 219259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 220259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 221259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return result; 222259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 223259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 224259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public static String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) { 225259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (tm == null) { 226259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "No valid TelephonyManager"); 227259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return null; 228259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 229259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills StringBuilder sb = new StringBuilder(); 230259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills for (String challenge : requestData) { 231259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (challenge == null || challenge.isEmpty()) { 232259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills continue; 233259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 234259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.d(TAG, "RAND = " + challenge); 235259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 236259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte[] rand = null; 237259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills try { 238259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills rand = parseHex(challenge); 239259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } catch (NumberFormatException e) { 240259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "malformed challenge"); 241259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills continue; 242259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 243259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 244259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String base64Challenge = Base64.encodeToString(rand, Base64.NO_WRAP); 245259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 246259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills // Try USIM first for authentication. 247259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM, 248259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge); 249259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (tmResponse == null) { 250259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills // Then, in case of failure, issue may be due to sim type, retry as a simple sim 251259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_SIM, 252259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge); 253259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 254259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.v(TAG, "Raw Response - " + tmResponse); 255259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 256259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (tmResponse == null || tmResponse.length() <= 4) { 257259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "bad response - " + tmResponse); 258259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return null; 259259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 260259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 261259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte[] result = Base64.decode(tmResponse, Base64.DEFAULT); 262259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.v(TAG, "Hex Response -" + makeHex(result)); 263259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int sresLen = result[0]; 264259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (sresLen >= result.length) { 265259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "malfomed response - " + tmResponse); 266259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return null; 267259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 268259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String sres = makeHex(result, 1, sresLen); 269259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int kcOffset = 1 + sresLen; 270259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (kcOffset >= result.length) { 271259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "malfomed response - " + tmResponse); 272259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return null; 273259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 274259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int kcLen = result[kcOffset]; 275259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (kcOffset + kcLen > result.length) { 276259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "malfomed response - " + tmResponse); 277259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return null; 278259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 279259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String kc = makeHex(result, 1 + kcOffset, kcLen); 280259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills sb.append(":" + kc + ":" + sres); 281259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.v(TAG, "kc:" + kc + " sres:" + sres); 282259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 283259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 284259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return sb.toString(); 285259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 286259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 287259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills /** 288259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills * Data supplied when making a SIM Auth Request 289259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills */ 290259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public static class SimAuthRequestData { 291259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public SimAuthRequestData() {} 292259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public SimAuthRequestData(int networkId, int protocol, String ssid, String[] data) { 293259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills this.networkId = networkId; 294259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills this.protocol = protocol; 295259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills this.ssid = ssid; 296259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills this.data = data; 297259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 298259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 299259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public int networkId; 300259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public int protocol; 301259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public String ssid; 302259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges 303259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge 304259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public String[] data; 305259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 306259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 307259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills /** 308259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills * The response to a SIM Auth request if successful 309259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills */ 310259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public static class SimAuthResponseData { 311259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public SimAuthResponseData(String type, String response) { 312259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills this.type = type; 313259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills this.response = response; 314259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 315259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 316259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public String type; 317259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public String response; 318259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 319259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 320259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills public static SimAuthResponseData get3GAuthResponse(SimAuthRequestData requestData, 321259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills TelephonyManager tm) { 322259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills StringBuilder sb = new StringBuilder(); 323259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte[] rand = null; 324259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte[] authn = null; 325b8b3fb8228a1f90106bad8c59ce006b81ef7921cRoshan Pius String resType = WifiNative.SIM_AUTH_RESP_TYPE_UMTS_AUTH; 326259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 327259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (requestData.data.length == 2) { 328259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills try { 329259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills rand = parseHex(requestData.data[0]); 330259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills authn = parseHex(requestData.data[1]); 331259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } catch (NumberFormatException e) { 332259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "malformed challenge"); 333259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 334259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else { 335259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "malformed challenge"); 336259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 337259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 338259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String tmResponse = ""; 339259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (rand != null && authn != null) { 340259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String base64Challenge = Base64.encodeToString(concatHex(rand, authn), Base64.NO_WRAP); 341259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (tm != null) { 342259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM, 343259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills TelephonyManager.AUTHTYPE_EAP_AKA, base64Challenge); 344259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.v(TAG, "Raw Response - " + tmResponse); 345259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else { 346259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "No valid TelephonyManager"); 347259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 348259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 349259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 350259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills boolean goodReponse = false; 351259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (tmResponse != null && tmResponse.length() > 4) { 352259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte[] result = Base64.decode(tmResponse, Base64.DEFAULT); 353259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "Hex Response - " + makeHex(result)); 354259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills byte tag = result[0]; 355259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (tag == (byte) 0xdb) { 356259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.v(TAG, "successful 3G authentication "); 357259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int resLen = result[1]; 358259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String res = makeHex(result, 2, resLen); 359259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int ckLen = result[resLen + 2]; 360259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String ck = makeHex(result, resLen + 3, ckLen); 361259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int ikLen = result[resLen + ckLen + 3]; 362259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String ik = makeHex(result, resLen + ckLen + 4, ikLen); 363259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills sb.append(":" + ik + ":" + ck + ":" + res); 364259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.v(TAG, "ik:" + ik + "ck:" + ck + " res:" + res); 365259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills goodReponse = true; 366259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else if (tag == (byte) 0xdc) { 367259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "synchronisation failure"); 368259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills int autsLen = result[1]; 369259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String auts = makeHex(result, 2, autsLen); 370b8b3fb8228a1f90106bad8c59ce006b81ef7921cRoshan Pius resType = WifiNative.SIM_AUTH_RESP_TYPE_UMTS_AUTS; 371259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills sb.append(":" + auts); 372259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.v(TAG, "auts:" + auts); 373259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills goodReponse = true; 374259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else { 375259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "bad response - unknown tag = " + tag); 376259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 377259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else { 378259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.e(TAG, "bad response - " + tmResponse); 379259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 380259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills 381259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills if (goodReponse) { 382259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills String response = sb.toString(); 383259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills Log.v(TAG, "Supplicant Response -" + response); 384259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return new SimAuthResponseData(resType, response); 385259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } else { 386259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills return null; 387259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 388259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills } 3893c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills} 390