diff options
author | Ecco Park <eccopark@google.com> | 2019-04-15 14:49:19 -0700 |
---|---|---|
committer | Ecco Park <eccopark@google.com> | 2019-04-17 13:31:20 -0700 |
commit | 1a859e8e16d693e245edabd95411888e9157a585 (patch) | |
tree | b64864fceaad2cd7fb5fb4e7504e6fa89cc3f830 /service | |
parent | 43c1e848f2b848a02738f3ccce7440c331e9262b (diff) |
carrier-wifi: support encrypted identity for V1.6
Encrypted identity for V1.6 requires to encrypt permanent_identity@NAIRealm
while the encrypted identity for V1.0 requires to encrypt permanent_identity
only.
Define additional sequence flag to specify the sequence that it sends
anonymous identity and then permanent identity for v1.6
Bug: 130569681
Test: unit test
Change-Id: Ia0d263ed2704fe2c83fe1501092a5ffe454ec0c3
Signed-off-by: Ecco Park <eccopark@google.com>
Diffstat (limited to 'service')
5 files changed, 109 insertions, 30 deletions
diff --git a/service/java/com/android/server/wifi/CarrierNetworkConfig.java b/service/java/com/android/server/wifi/CarrierNetworkConfig.java index 56e7c261b..1814eecf4 100644 --- a/service/java/com/android/server/wifi/CarrierNetworkConfig.java +++ b/service/java/com/android/server/wifi/CarrierNetworkConfig.java @@ -61,7 +61,7 @@ public class CarrierNetworkConfig { private final Map<String, NetworkInfo> mCarrierNetworkMap; private boolean mIsCarrierImsiEncryptionInfoAvailable = false; private int mBase64EncodingMethod = Base64.DEFAULT; - private int mEapIdentitySequence = IDENTITY_SEQUENCE_IMSI; + private int mEapIdentitySequence = IDENTITY_SEQUENCE_IMSI_V1_0; private ImsiEncryptionInfo mLastImsiEncryptionInfo = null; // used for dumpsys only // RFC2045: adds Line Feed at each 76 chars and encode it. @@ -70,8 +70,20 @@ public class CarrierNetworkConfig { // RFC4648: encodes whole data into one string. public static final int ENCODING_METHOD_RFC_4648 = 4648; - public static final int IDENTITY_SEQUENCE_IMSI = 1; - public static final int IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI = 2; + // Send encrypted IMSI with the format of V1.0 + // V1.0 format: "\0"|<encrypted IMSI>|@NAIRealm + // <encrypted IMSI>: Base64{RSA Public Key Encryption{<permanent ID>}} + // <permanent ID>: One char ("0" for AKA, "1" for SIM, "6" for AKA')|IMSI + public static final int IDENTITY_SEQUENCE_IMSI_V1_0 = 1; + + // Send anonymous identity and encrypted IMSI identity with the format of V1.0 + public static final int IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_0 = 2; + + // Send anonymous identity and encrypted IMSI identity with the format of V1.6 + // V1.6 format: "\0"|<encrypted identity> + // <encrypted identity>: Base64{RSA Public Key Encryption{<permanent ID>}}. + // <permanent ID>: One char ("0" for AKA, "1" for SIM, "6" for AKA')|IMSI|@NAIRealm + public static final int IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_6 = 3; /** * Enable/disable verbose logging. @@ -144,6 +156,15 @@ public class CarrierNetworkConfig { } /** + * @return {@code true} if current carrier wifi network supports anonymous identity, {@code + * false} otherwise. + */ + public boolean isSupportAnonymousIdentity() { + return mEapIdentitySequence == IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_0 + || mEapIdentitySequence == IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_6; + } + + /** * @return True if carrier IMSI encryption info is available, False otherwise. */ public boolean isCarrierEncryptionInfoAvailable() { @@ -268,9 +289,10 @@ public class CarrierNetworkConfig { } int sequence = carrierConfig.getInt(CarrierConfigManager.KEY_EAP_IDENTITY_SEQUENCE_INT, - IDENTITY_SEQUENCE_IMSI); - if (sequence != IDENTITY_SEQUENCE_IMSI - && sequence != IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI) { + IDENTITY_SEQUENCE_IMSI_V1_0); + if (sequence != IDENTITY_SEQUENCE_IMSI_V1_0 + && sequence != IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_0 + && sequence != IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_6) { Log.e(TAG, "Invalid eap identity sequence: " + sequence); return; } diff --git a/service/java/com/android/server/wifi/CarrierNetworkEvaluator.java b/service/java/com/android/server/wifi/CarrierNetworkEvaluator.java index fd143529b..3b19eaff8 100644 --- a/service/java/com/android/server/wifi/CarrierNetworkEvaluator.java +++ b/service/java/com/android/server/wifi/CarrierNetworkEvaluator.java @@ -161,8 +161,7 @@ public class CarrierNetworkEvaluator implements NetworkEvaluator { // In case of a carrier supporting anonymous identity, we need // to send anonymous@realm as EAP-IDENTITY response. - if (mCarrierNetworkConfig.getEapIdentitySequence() - == CarrierNetworkConfig.IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI) { + if (mCarrierNetworkConfig.isSupportAnonymousIdentity()) { config.enterpriseConfig.setAnonymousIdentity( TelephonyUtil.getAnonymousIdentityWith3GppRealm(getTelephonyManager())); } diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 0bdd37b1a..2ae6b4ed5 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -23,8 +23,6 @@ import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; -import static com.android.server.wifi.CarrierNetworkConfig.IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI; - import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -4434,9 +4432,8 @@ public class ClientModeImpl extends StateMachine { } else { CarrierNetworkConfig carrierNetworkConfig = mWifiInjector.getCarrierNetworkConfig(); - if (carrierNetworkConfig.isCarrierEncryptionInfoAvailable() && ( - carrierNetworkConfig.getEapIdentitySequence() - == IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI)) { + if (carrierNetworkConfig.isCarrierEncryptionInfoAvailable() + && carrierNetworkConfig.isSupportAnonymousIdentity()) { // In case of a carrier supporting encrypted IMSI and // anonymous identity, we need to send anonymous@realm as // EAP-IDENTITY response. diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java index 9f76a2782..58c51486d 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java @@ -188,8 +188,7 @@ public class PasspointNetworkEvaluator implements WifiNetworkSelector.NetworkEva WifiConfiguration config = networkInfo.mProvider.getWifiConfig(); if (TelephonyUtil.isSimEapMethod(config.enterpriseConfig.getEapMethod()) && mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable() - && (mCarrierNetworkConfig.getEapIdentitySequence() - == CarrierNetworkConfig.IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI)) { + && mCarrierNetworkConfig.isSupportAnonymousIdentity()) { // In case of a carrier supporting encrypted IMSI and anonymous identity, we need // to send anonymous@realm as EAP-IDENTITY response. config.enterpriseConfig.setAnonymousIdentity( diff --git a/service/java/com/android/server/wifi/util/TelephonyUtil.java b/service/java/com/android/server/wifi/util/TelephonyUtil.java index 873fda528..80cadc0af 100644 --- a/service/java/com/android/server/wifi/util/TelephonyUtil.java +++ b/service/java/com/android/server/wifi/util/TelephonyUtil.java @@ -16,6 +16,10 @@ package com.android.server.wifi.util; +import static com.android.server.wifi.CarrierNetworkConfig.IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_0; +import static com.android.server.wifi.CarrierNetworkConfig.IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_6; +import static com.android.server.wifi.CarrierNetworkConfig.IDENTITY_SEQUENCE_IMSI_V1_0; + import android.annotation.NonNull; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; @@ -102,6 +106,12 @@ public class TelephonyUtil { mccMnc = tm.getSimOperator(); } + String identity = buildIdentity(getSimMethodForConfig(config), imsi, mccMnc, false); + if (identity == null) { + Log.e(TAG, "Failed to build the identity"); + return null; + } + ImsiEncryptionInfo imsiEncryptionInfo; try { imsiEncryptionInfo = tm.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_WLAN); @@ -109,21 +119,30 @@ public class TelephonyUtil { Log.e(TAG, "Failed to get imsi encryption info: " + e.getMessage()); return null; } - - String identity = buildIdentity(getSimMethodForConfig(config), imsi, mccMnc, false); - if (identity == null) { - Log.e(TAG, "Failed to build the identity"); - return null; + if (imsiEncryptionInfo == null) { + // Does not support encrypted identity. + return Pair.create(identity, ""); } int base64EncodingFlag = carrierNetworkConfig.getBase64EncodingFlag(); - String encryptedIdentity = buildEncryptedIdentity(telephonyUtil, - getSimMethodForConfig(config), imsi, mccMnc, imsiEncryptionInfo, - base64EncodingFlag); - - // In case of failure for encryption, set empty string - if (encryptedIdentity == null) encryptedIdentity = ""; + String encryptedIdentity = null; + int eapSequence = carrierNetworkConfig.getEapIdentitySequence(); + if (eapSequence == IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_6) { + encryptedIdentity = buildEncryptedIdentityV1_6(telephonyUtil, identity, + imsiEncryptionInfo, base64EncodingFlag); + } else if (eapSequence == IDENTITY_SEQUENCE_IMSI_V1_0 + || eapSequence == IDENTITY_SEQUENCE_ANONYMOUS_THEN_IMSI_V1_0) { + encryptedIdentity = buildEncryptedIdentityV1_0(telephonyUtil, + getSimMethodForConfig(config), imsi, mccMnc, imsiEncryptionInfo, + base64EncodingFlag); + } + + // In case of failure for encryption, abort current EAP authentication. + if (encryptedIdentity == null) { + Log.e(TAG, "failed to encrypt the identity, eapIdentitySequence: " + eapSequence); + return null; + } return Pair.create(identity, encryptedIdentity); } @@ -179,19 +198,21 @@ public class TelephonyUtil { } /** - * Create the encrypted IMSI. - * Prefix value: + * Create the encrypted identity for V1.0. + * + * Prefix value: * "0" - EAP-AKA Identity * "1" - EAP-SIM Identity * "6" - EAP-AKA' Identity - * + * Encrypted Identity format for V1.0: prefix|IMSI * @param eapMethod EAP authentication method: EAP-SIM, EAP-AKA, EAP-AKA' * @param imsi The IMSI retrieved from the SIM * @param mccMnc The MCC MNC identifier retrieved from the SIM * @param imsiEncryptionInfo The IMSI encryption info retrieved from the SIM * @param base64EncodingFlag base64 encoding flag + * @return "\0" + encryptedIdentity@<NAIRealm> + "{, Key Identifier AVP}" */ - private static String buildEncryptedIdentity(TelephonyUtil telephonyUtil, int eapMethod, + private static String buildEncryptedIdentityV1_0(TelephonyUtil telephonyUtil, int eapMethod, String imsi, String mccMnc, ImsiEncryptionInfo imsiEncryptionInfo, int base64EncodingFlag) { if (imsiEncryptionInfo == null) { @@ -220,6 +241,47 @@ public class TelephonyUtil { } /** + * Create the encrypted identity for V1.6. + * + * Prefix value: + * "0" - EAP-AKA Identity + * "1" - EAP-SIM Identity + * "6" - EAP-AKA' Identity + * Encrypted identity format for V1.6: prefix|IMSI@<NAIRealm> + * @param telephonyUtil TelephonyUtil instance + * @param identity permanent identity with format based on section 4.1.1.6 of RFC 4187 + * and 4.2.1.6 of RFC 4186. + * @param imsiEncryptionInfo The IMSI encryption info retrieved from the SIM + * @param base64EncodingFlag base64 encoding flag + * @return "\0" + encryptedIdentity + "{, Key Identifier AVP}" + */ + private static String buildEncryptedIdentityV1_6(TelephonyUtil telephonyUtil, String identity, + ImsiEncryptionInfo imsiEncryptionInfo, int base64EncodingFlag) { + if (imsiEncryptionInfo == null) { + Log.e(TAG, "imsiEncryptionInfo is not valid"); + return null; + } + if (identity == null) { + Log.e(TAG, "identity is not valid"); + return null; + } + + // Build and return the encrypted identity. + String encryptedIdentity = telephonyUtil.encryptDataUsingPublicKey( + imsiEncryptionInfo.getPublicKey(), identity.getBytes(), base64EncodingFlag); + if (encryptedIdentity == null) { + Log.e(TAG, "Failed to encrypt IMSI"); + return null; + } + encryptedIdentity = DEFAULT_EAP_PREFIX + encryptedIdentity; + if (imsiEncryptionInfo.getKeyIdentifier() != null) { + // Include key identifier AVP (Attribute Value Pair). + encryptedIdentity = encryptedIdentity + "," + imsiEncryptionInfo.getKeyIdentifier(); + } + return encryptedIdentity; + } + + /** * Create an identity used for SIM-based EAP authentication. The identity will be based on * the info retrieved from the SIM card, such as IMSI and IMSI encryption info. The IMSI * contained in the identity will be encrypted if IMSI encryption info is provided. |