WIFI: EAP-AKA End-To-End

 - Decode UMTS-AUTH form of CTRL-REQ-SIM request
 - manage UMTS authentication
 - cleanup useless code
 - make Native API simAuthResponse usable for both
   EAP-SIM and EAP-AKA

Change-Id: Ie24c59d87ba2e6a17a0da25fa3d58803aab423f9
Signed-off-by: Honore Tricot <honorex.tricot@intel.com>
Signed-off-by: Abdelmajid MLAYEH <abdelmajidx.mlayeh@intel.com>
diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java
index 97e8824..227c8d2 100644
--- a/service/java/com/android/server/wifi/WifiMonitor.java
+++ b/service/java/com/android/server/wifi/WifiMonitor.java
@@ -278,6 +278,19 @@
             Pattern.compile("SIM-([0-9]*):GSM-AUTH((:[0-9a-f]+)+) needed for SSID (.+)");
 
     /**
+     * Regex pattern for extracting an external 3G sim authentication request from a string.
+     * Matches a strings like the following:<pre>
+     * CTRL-REQ-SIM-<network id>:UMTS-AUTH:<RAND>:<AUTN> needed for SSID <SSID>
+     * This pattern should find
+     *    1 - id
+     *    2 - Rand
+     *    3 - Autn
+     *    4 - SSID
+     */
+    private static Pattern mRequestUmtsAuthPattern =
+            Pattern.compile("SIM-([0-9]*):UMTS-AUTH:([0-9a-f]+):([0-9a-f]+) needed for SSID (.+)");
+
+    /**
      * Regex pattern for extracting SSIDs from request identity string.
      * Matches a strings like the following:<pre>
      * CTRL-REQ-IDENTITY-xx:Identity needed for SSID XXXX</pre>
@@ -1248,14 +1261,23 @@
             }
             mStateMachine.sendMessage(SUP_REQUEST_IDENTITY, eventLogCounter, reason, SSID);
         } else if (requestName.startsWith(SIM_STR)) {
-            Matcher match = mRequestGsmAuthPattern.matcher(requestName);
-            if (match.find()) {
-                WifiStateMachine.SimAuthRequestData data =
-                        new WifiStateMachine.SimAuthRequestData();
-                data.networkId = Integer.parseInt(match.group(1));
+            Matcher matchGsm = mRequestGsmAuthPattern.matcher(requestName);
+            Matcher matchUmts = mRequestUmtsAuthPattern.matcher(requestName);
+            WifiStateMachine.SimAuthRequestData data =
+                    new WifiStateMachine.SimAuthRequestData();
+            if (matchGsm.find()) {
+                data.networkId = Integer.parseInt(matchGsm.group(1));
                 data.protocol = WifiEnterpriseConfig.Eap.SIM;
-                data.ssid = match.group(4);
-                data.challenges = match.group(2).split(":");
+                data.ssid = matchGsm.group(4);
+                data.data = matchGsm.group(2).split(":");
+                mStateMachine.sendMessage(SUP_REQUEST_SIM_AUTH, data);
+            } else if (matchUmts.find()) {
+                data.networkId = Integer.parseInt(matchUmts.group(1));
+                data.protocol = WifiEnterpriseConfig.Eap.AKA;
+                data.ssid = matchUmts.group(4);
+                data.data = new String[2];
+                data.data[0] = matchUmts.group(2);
+                data.data[1] = matchUmts.group(3);
                 mStateMachine.sendMessage(SUP_REQUEST_SIM_AUTH, data);
             } else {
                 Log.e(TAG, "couldn't parse SIM auth request - " + requestName);
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index f35ef61..8b9a524 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -732,9 +732,10 @@
         }
     }
 
-    public boolean simAuthResponse(int id, String response) {
+    public boolean simAuthResponse(int id, String type, String response) {
+        // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS
         synchronized (mLock) {
-            return doBooleanCommand("CTRL-RSP-SIM-" + id + ":GSM-AUTH" + response);
+            return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response);
         }
     }
 
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 1076e40..95d90bf 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -798,17 +798,9 @@
         int networkId;
         int protocol;
         String ssid;
-        String[] challenges;
-    }
-
-    public static class SimAuthResponseData {
-        int id;
-        String Kc1;
-        String SRES1;
-        String Kc2;
-        String SRES2;
-        String Kc3;
-        String SRES3;
+        // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges
+        // EAP-AKA: data[] contains rand & authn couple for the single challenge
+        String[] data;
     }
 
     /**
@@ -8708,7 +8700,6 @@
         return sb.toString();
     }
 
-
     private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
 
         int len = array1.length + array2.length + array3.length;
@@ -8757,6 +8748,30 @@
         return result;
     }
 
+    private static byte[] concatHex(byte[] array1, byte[] array2) {
+
+        int len = array1.length + array2.length;
+
+        byte[] result = new byte[len];
+
+        int index = 0;
+        if (array1.length != 0) {
+            for (byte b : array1) {
+                result[index] = b;
+                index++;
+            }
+        }
+
+        if (array2.length != 0) {
+            for (byte b : array2) {
+                result[index] = b;
+                index++;
+            }
+        }
+
+        return result;
+    }
+
     void handleGsmAuthRequest(SimAuthRequestData requestData) {
         if (targetWificonfiguration == null
                 || targetWificonfiguration.networkId == requestData.networkId) {
@@ -8771,7 +8786,7 @@
 
         if (tm != null) {
             StringBuilder sb = new StringBuilder();
-            for (String challenge : requestData.challenges) {
+            for (String challenge : requestData.data) {
 
                 logd("RAND = " + challenge);
 
@@ -8811,13 +8826,85 @@
 
             String response = sb.toString();
             logv("Supplicant Response -" + response);
-            mWifiNative.simAuthResponse(requestData.networkId, response);
+            mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
         } else {
             loge("could not get telephony manager");
         }
     }
 
     void handle3GAuthRequest(SimAuthRequestData requestData) {
+        StringBuilder sb = new StringBuilder();
+        byte[] rand = null;
+        byte[] authn = null;
+        String res_type = "UMTS-AUTH";
 
+        if (targetWificonfiguration == null
+                || targetWificonfiguration.networkId == requestData.networkId) {
+            logd("id matches targetWifiConfiguration");
+        } else {
+            logd("id does not match targetWifiConfiguration");
+            return;
+        }
+        if (requestData.data.length == 2) {
+            try {
+                rand = parseHex(requestData.data[0]);
+                authn = parseHex(requestData.data[1]);
+            } catch (NumberFormatException e) {
+                loge("malformed challenge");
+            }
+        } else {
+               loge("malformed challenge");
+        }
+
+        String tmResponse = "";
+        if (rand != null && authn != null) {
+            String base64Challenge = android.util.Base64.encodeToString(
+                    concatHex(rand,authn), android.util.Base64.NO_WRAP);
+
+            TelephonyManager tm = (TelephonyManager)
+                    mContext.getSystemService(Context.TELEPHONY_SERVICE);
+            if (tm != null) {
+                int appType = 2; // 2 => USIM
+                tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
+                logv("Raw Response - " + tmResponse);
+            } else {
+                loge("could not get telephony manager");
+            }
+        }
+
+        if (tmResponse != null && tmResponse.length() > 4) {
+            byte[] result = android.util.Base64.decode(tmResponse,
+                    android.util.Base64.DEFAULT);
+            loge("Hex Response - " + makeHex(result));
+            byte tag = result[0];
+            if (tag == (byte) 0xdb) {
+                logv("successful 3G authentication ");
+                int res_len = result[1];
+                String res = makeHex(result, 2, res_len);
+                int ck_len = result[res_len + 2];
+                String ck = makeHex(result, res_len + 3, ck_len);
+                int ik_len = result[res_len + ck_len + 3];
+                String ik = makeHex(result, res_len + ck_len + 4, ik_len);
+                sb.append(":" + ik + ":" + ck + ":" + res);
+                logv("ik:" + ik + "ck:" + ck + " res:" + res);
+            } else if (tag == (byte) 0xdc) {
+                loge("synchronisation failure");
+                int auts_len = result[1];
+                String auts = makeHex(result, 2, auts_len);
+                res_type = "UMTS-AUTS";
+                sb.append(":" + auts);
+                logv("auts:" + auts);
+            } else {
+                loge("bad response - unknown tag = " + tag);
+                return;
+            }
+        } else {
+            loge("bad response - " + tmResponse);
+            return;
+        }
+
+        String response = sb.toString();
+        logv("Supplicant Response -" + response);
+        mWifiNative.simAuthResponse(requestData.networkId, res_type, response);
     }
 }