aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/java/com/android/ike/eap/EapSessionConfig.java46
-rw-r--r--src/java/com/android/ike/eap/message/EapData.java1
-rw-r--r--src/java/com/android/ike/eap/message/simaka/EapAkaAttributeFactory.java24
-rw-r--r--src/java/com/android/ike/eap/message/simaka/EapAkaPrimeAttributeFactory.java77
-rw-r--r--src/java/com/android/ike/eap/message/simaka/EapAkaPrimeTypeData.java95
-rw-r--r--src/java/com/android/ike/eap/message/simaka/EapAkaTypeData.java2
-rw-r--r--src/java/com/android/ike/eap/message/simaka/EapSimAkaAttribute.java121
-rw-r--r--src/java/com/android/ike/eap/message/simaka/EapSimAkaAttributeFactory.java13
-rw-r--r--src/java/com/android/ike/eap/statemachine/EapAkaMethodStateMachine.java73
-rw-r--r--src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachine.java136
-rw-r--r--src/java/com/android/ike/eap/statemachine/EapStateMachine.java8
-rw-r--r--src/java/com/android/ike/ikev2/IkeSessionOptions.java31
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/EapSessionConfigTest.java27
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/message/EapTestMessageDefinitions.java13
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeTypeDataTest.java142
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtBiddingTest.java99
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtKdfInputTest.java78
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtKdfTest.java78
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/EapTestAttributeDefinitions.java14
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaIdentityStateTest.java1
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeChallengeStateTest.java111
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeCreatedStateTest.java85
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeIdentityStateTest.java96
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java30
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeStateTest.java100
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeTest.java78
-rw-r--r--tests/iketests/src/java/com/android/ike/eap/statemachine/MethodStateTest.java20
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java21
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java4
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/IkeSessionTest.java5
30 files changed, 1562 insertions, 67 deletions
diff --git a/src/java/com/android/ike/eap/EapSessionConfig.java b/src/java/com/android/ike/eap/EapSessionConfig.java
index e3729e3c..285dc799 100644
--- a/src/java/com/android/ike/eap/EapSessionConfig.java
+++ b/src/java/com/android/ike/eap/EapSessionConfig.java
@@ -17,6 +17,7 @@
package com.android.ike.eap;
import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA;
+import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME;
import static com.android.ike.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
import static com.android.ike.eap.message.EapData.EAP_TYPE_SIM;
@@ -99,6 +100,31 @@ public final class EapSessionConfig {
}
/**
+ * Sets the configuration for EAP AKA'.
+ *
+ * @param subId int the client's subId to be authenticated
+ * @param apptype the {@link UiccAppType} apptype to be used for authentication
+ * @param networkName String the network name to be used for authentication. The String must
+ * be a UTF-8 String value
+ * @param allowMismatchedNetworkNames indicates whether the EAP library can ignore potential
+ * mismatches between the given network name and that received in an EAP-AKA' session.
+ * If false, mismatched network names will be handled as an Authentication Reject
+ * message.
+ * @return Builder this, to facilitate chaining
+ */
+ public Builder setEapAkaPrimeConfig(
+ int subId,
+ @UiccAppType int apptype,
+ String networkName,
+ boolean allowMismatchedNetworkNames) {
+ mEapConfigs.put(
+ EAP_TYPE_AKA_PRIME,
+ new EapAkaPrimeConfig(
+ subId, apptype, networkName, allowMismatchedNetworkNames));
+ return this;
+ }
+
+ /**
* Sets the configuration for EAP MSCHAPv2.
*
* @param username String the client account's username to be authenticated
@@ -171,6 +197,26 @@ public final class EapSessionConfig {
}
/**
+ * EapAkaPrimeConfig represents the configs needed for an EAP-AKA' session.
+ */
+ public static class EapAkaPrimeConfig extends EapAkaConfig {
+ public final String networkName;
+ public final boolean allowMismatchedNetworkNames;
+
+ @VisibleForTesting
+ public EapAkaPrimeConfig(
+ int subId,
+ @UiccAppType int apptype,
+ String networkName,
+ boolean allowMismatchedNetworkNames) {
+ super(subId, apptype);
+
+ this.networkName = networkName;
+ this.allowMismatchedNetworkNames = allowMismatchedNetworkNames;
+ }
+ }
+
+ /**
* EapMsChapV2Config represents the configs needed for an EAP MSCHAPv2 session.
*/
public static class EapMsChapV2Config extends EapMethodConfig {
diff --git a/src/java/com/android/ike/eap/message/EapData.java b/src/java/com/android/ike/eap/message/EapData.java
index 122579c1..5e317160 100644
--- a/src/java/com/android/ike/eap/message/EapData.java
+++ b/src/java/com/android/ike/eap/message/EapData.java
@@ -100,6 +100,7 @@ public class EapData {
SUPPORTED_TYPES.add(EAP_TYPE_SIM);
SUPPORTED_TYPES.add(EAP_TYPE_AKA);
SUPPORTED_TYPES.add(EAP_TYPE_MSCHAP_V2);
+ SUPPORTED_TYPES.add(EAP_TYPE_AKA_PRIME);
}
@EapType public final int eapType;
diff --git a/src/java/com/android/ike/eap/message/simaka/EapAkaAttributeFactory.java b/src/java/com/android/ike/eap/message/simaka/EapAkaAttributeFactory.java
index a038316f..2a0c738a 100644
--- a/src/java/com/android/ike/eap/message/simaka/EapAkaAttributeFactory.java
+++ b/src/java/com/android/ike/eap/message/simaka/EapAkaAttributeFactory.java
@@ -18,6 +18,7 @@ package com.android.ike.eap.message.simaka;
import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN;
import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTS;
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_BIDDING;
import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RES;
import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.LENGTH_SCALING;
@@ -26,6 +27,7 @@ import com.android.ike.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
import com.android.ike.eap.exceptions.simaka.EapSimAkaUnsupportedAttributeException;
import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtAutn;
import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtAuts;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtBidding;
import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtRes;
@@ -42,8 +44,7 @@ import java.nio.ByteBuffer;
public class EapAkaAttributeFactory extends EapSimAkaAttributeFactory {
private static EapAkaAttributeFactory sInstance = new EapAkaAttributeFactory();
- private EapAkaAttributeFactory() {
- }
+ protected EapAkaAttributeFactory() {}
public static EapAkaAttributeFactory getInstance() {
return sInstance;
@@ -56,19 +57,26 @@ public class EapAkaAttributeFactory extends EapSimAkaAttributeFactory {
*
* @param byteBuffer The ByteBuffer to parse the current attribute from
* @return The current EapSimAkaAttribute to be parsed, or EapSimAkaUnsupportedAttribute if the
- * given attributeType is skippable and unsupported
+ * given attributeType is skippable and unsupported
* @throws EapSimAkaInvalidAttributeException when a malformatted attribute is attempted to be
- * decoded
+ * decoded
* @throws EapSimAkaUnsupportedAttributeException when an unsupported, unskippable Attribute is
- * attempted to be decoded
+ * attempted to be decoded
*/
- public EapSimAkaAttribute getAttribute(ByteBuffer byteBuffer) throws
- EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
+ public EapSimAkaAttribute getAttribute(ByteBuffer byteBuffer)
+ throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
int attributeType = Byte.toUnsignedInt(byteBuffer.get());
// Length is given as a multiple of 4x bytes (RFC 4187#8.1)
int lengthInBytes = Byte.toUnsignedInt(byteBuffer.get()) * LENGTH_SCALING;
+ return getAttribute(attributeType, lengthInBytes, byteBuffer);
+ }
+
+ @Override
+ protected EapSimAkaAttribute getAttribute(
+ int attributeType, int lengthInBytes, ByteBuffer byteBuffer)
+ throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
switch (attributeType) {
case EAP_AT_RAND:
return new AtRandAka(lengthInBytes, byteBuffer);
@@ -78,6 +86,8 @@ public class EapAkaAttributeFactory extends EapSimAkaAttributeFactory {
return new AtRes(lengthInBytes, byteBuffer);
case EAP_AT_AUTS:
return new AtAuts(lengthInBytes, byteBuffer);
+ case EAP_AT_BIDDING:
+ return new AtBidding(lengthInBytes, byteBuffer);
default:
return super.getAttribute(attributeType, lengthInBytes, byteBuffer);
}
diff --git a/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeAttributeFactory.java b/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeAttributeFactory.java
new file mode 100644
index 00000000..ed7ddc5b
--- /dev/null
+++ b/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeAttributeFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.message.simaka;
+
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF;
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF_INPUT;
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.LENGTH_SCALING;
+
+import com.android.ike.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
+import com.android.ike.eap.exceptions.simaka.EapSimAkaUnsupportedAttributeException;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtKdf;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtKdfInput;
+
+import java.nio.ByteBuffer;
+
+/**
+ * EapAkaPrimeAttributeFactory is used for creating EAP-AKA' attributes according to their type.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc5448">RFC 5448, Improved Extensible Authentication
+ * Protocol Method for 3rd Generation Authentication and Key Agreement (EAP-AKA')</a>
+ * @see <a href="https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml">EAP SIM/AKA
+ * Attributes</a>
+ */
+public class EapAkaPrimeAttributeFactory extends EapAkaAttributeFactory {
+ private static EapAkaPrimeAttributeFactory sInstance = new EapAkaPrimeAttributeFactory();
+
+ private EapAkaPrimeAttributeFactory() {}
+
+ public static EapAkaPrimeAttributeFactory getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * Decodes a single EapSimAkaAttribute object from the given ByteBuffer.
+ *
+ * <p>Decoding logic is based on Attribute definitions in RFC 5448#10.
+ *
+ * @param byteBuffer The ByteBuffer to parse the current attribute from
+ * @return The current EapSimAkaAttribute to be parsed, or EapSimAkaUnsupportedAttribute if the
+ * given attributeType is skippable and unsupported
+ * @throws EapSimAkaInvalidAttributeException when a malformatted attribute is attempted to be
+ * decoded
+ * @throws EapSimAkaUnsupportedAttributeException when an unsupported, unskippable Attribute is
+ * attempted to be decoded
+ */
+ @Override
+ public EapSimAkaAttribute getAttribute(ByteBuffer byteBuffer)
+ throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
+ int attributeType = Byte.toUnsignedInt(byteBuffer.get());
+
+ // Length is given as a multiple of 4x bytes (RFC 4187#8.1)
+ int lengthInBytes = Byte.toUnsignedInt(byteBuffer.get()) * LENGTH_SCALING;
+
+ switch (attributeType) {
+ case EAP_AT_KDF_INPUT:
+ return new AtKdfInput(lengthInBytes, byteBuffer);
+ case EAP_AT_KDF:
+ return new AtKdf(lengthInBytes, byteBuffer);
+ default:
+ return super.getAttribute(attributeType, lengthInBytes, byteBuffer);
+ }
+ }
+}
diff --git a/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeTypeData.java b/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeTypeData.java
new file mode 100644
index 00000000..7f06d683
--- /dev/null
+++ b/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeTypeData.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.message.simaka;
+
+import android.annotation.NonNull;
+
+import com.android.ike.eap.message.EapMessage;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * EapAkaPrimeTypeData represents the Type Data for an {@link EapMessage} during an EAP-AKA'
+ * session.
+ */
+public class EapAkaPrimeTypeData extends EapAkaTypeData {
+ private static final EapAkaPrimeTypeDataDecoder sTypeDataDecoder =
+ new EapAkaPrimeTypeDataDecoder();
+
+ @VisibleForTesting
+ EapAkaPrimeTypeData(
+ int eapSubType, LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
+ super(eapSubType, attributeMap);
+ }
+
+ /**
+ * Creates and returns an EapAkaPrimeTypeData instance with the given subtype and attributes.
+ *
+ * @param eapSubtype the subtype for the EAP-AKA type data
+ * @param attributes the List of EapSimAkaAttributes to be included in this type data
+ */
+ public EapAkaPrimeTypeData(int eapSubtype, List<EapSimAkaAttribute> attributes) {
+ super(eapSubtype, attributes);
+ }
+
+ public static EapAkaPrimeTypeDataDecoder getEapAkaPrimeTypeDataDecoder() {
+ return sTypeDataDecoder;
+ }
+
+ /**
+ * EapAkaTypeDataDecoder will be used for decoding {@link EapAkaPrimeTypeData} objects.
+ */
+ public static class EapAkaPrimeTypeDataDecoder
+ extends EapSimAkaTypeDataDecoder<EapAkaTypeData> {
+ private static final String TAG = EapAkaPrimeTypeDataDecoder.class.getSimpleName();
+ private static final String EAP_METHOD = "EAP-AKA'";
+
+ protected EapAkaPrimeTypeDataDecoder() {
+ super(
+ TAG,
+ EAP_METHOD,
+ SUPPORTED_SUBTYPES,
+ EapAkaPrimeAttributeFactory.getInstance(),
+ EAP_AKA_SUBTYPE_STRING);
+ }
+
+ /**
+ * Decodes the given byte-array into a DecodeResult object.
+ *
+ * <p>Note that <b>only 1 KDF value</b> is allowed. If multiple AT_KDF attributes are
+ * supplied, a {@link DecodeResult} wrapping a {@link AtClientErrorCode#UNABLE_TO_PROCESS}
+ * will be returned.
+ *
+ * @param typeData the byte-encoding of the EapAkaPrimeTypeData to be parsed
+ * @return a DecodeResult object. If the decoding is successful, this will encapsulate an
+ * EapAkaPrimeTypeData instance representing the data stored in typeData. Otherwise, it
+ * will contain the relevant AtClientErrorCode for the decoding error.
+ */
+ public DecodeResult<EapAkaTypeData> decode(@NonNull byte[] typeData) {
+ return super.decode(typeData);
+ }
+
+ @Override
+ protected EapAkaPrimeTypeData getInstance(
+ int eapSubtype, LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
+ return new EapAkaPrimeTypeData(eapSubtype, attributeMap);
+ }
+ }
+}
diff --git a/src/java/com/android/ike/eap/message/simaka/EapAkaTypeData.java b/src/java/com/android/ike/eap/message/simaka/EapAkaTypeData.java
index f8e0a3a3..ceee3e71 100644
--- a/src/java/com/android/ike/eap/message/simaka/EapAkaTypeData.java
+++ b/src/java/com/android/ike/eap/message/simaka/EapAkaTypeData.java
@@ -55,7 +55,7 @@ public class EapAkaTypeData extends EapSimAkaTypeData {
EAP_AKA_SUBTYPE_STRING.put(EAP_AKA_CLIENT_ERROR, "Client-Error");
}
- private static final Set<Integer> SUPPORTED_SUBTYPES = new HashSet<>();
+ protected static final Set<Integer> SUPPORTED_SUBTYPES = new HashSet<>();
static {
SUPPORTED_SUBTYPES.add(EAP_AKA_CHALLENGE);
SUPPORTED_SUBTYPES.add(EAP_AKA_AUTHENTICATION_REJECT);
diff --git a/src/java/com/android/ike/eap/message/simaka/EapSimAkaAttribute.java b/src/java/com/android/ike/eap/message/simaka/EapSimAkaAttribute.java
index b24b9f5f..dec511c7 100644
--- a/src/java/com/android/ike/eap/message/simaka/EapSimAkaAttribute.java
+++ b/src/java/com/android/ike/eap/message/simaka/EapSimAkaAttribute.java
@@ -67,6 +67,8 @@ public abstract class EapSimAkaAttribute {
public static final int EAP_AT_COUNTER_TOO_SMALL = 20;
public static final int EAP_AT_NONCE_S = 21;
public static final int EAP_AT_CLIENT_ERROR_CODE = 22;
+ public static final int EAP_AT_KDF_INPUT = 23;
+ public static final int EAP_AT_KDF = 24;
// EAP Skippable Attribute values defined by IANA
// https://www.iana.org/assignments/eapsimaka-numbers/eapsimaka-numbers.xhtml
@@ -76,6 +78,7 @@ public abstract class EapSimAkaAttribute {
public static final int EAP_AT_NEXT_REAUTH_ID = 133;
public static final int EAP_AT_CHECKCODE = 134;
public static final int EAP_AT_RESULT_IND = 135;
+ public static final int EAP_AT_BIDDING = 136;
public static final Map<Integer, String> EAP_ATTRIBUTE_STRING = new HashMap<>();
static {
@@ -97,6 +100,8 @@ public abstract class EapSimAkaAttribute {
EAP_ATTRIBUTE_STRING.put(EAP_AT_COUNTER_TOO_SMALL, "AT_COUNTER_TOO_SMALL");
EAP_ATTRIBUTE_STRING.put(EAP_AT_NONCE_S, "AT_NONCE_S");
EAP_ATTRIBUTE_STRING.put(EAP_AT_CLIENT_ERROR_CODE, "AT_CLIENT_ERROR_CODE");
+ EAP_ATTRIBUTE_STRING.put(EAP_AT_KDF_INPUT, "AT_KDF_INPUT");
+ EAP_ATTRIBUTE_STRING.put(EAP_AT_KDF, "AT_KDF");
EAP_ATTRIBUTE_STRING.put(EAP_AT_IV, "AT_IV");
EAP_ATTRIBUTE_STRING.put(EAP_AT_ENCR_DATA, "AT_ENCR_DATA");
@@ -104,6 +109,7 @@ public abstract class EapSimAkaAttribute {
EAP_ATTRIBUTE_STRING.put(EAP_AT_NEXT_REAUTH_ID, "AT_NEXT_REAUTH_ID");
EAP_ATTRIBUTE_STRING.put(EAP_AT_CHECKCODE, "AT_CHECKCODE");
EAP_ATTRIBUTE_STRING.put(EAP_AT_RESULT_IND, "AT_RESULT_IND");
+ EAP_ATTRIBUTE_STRING.put(EAP_AT_BIDDING, "AT_BIDDING");
}
public final int attributeType;
@@ -778,12 +784,10 @@ public abstract class EapSimAkaAttribute {
notificationCode = Short.toUnsignedInt(byteBuffer.getShort());
// If Success bit == 0, failure is implied
- isSuccessCode = (notificationCode & SUCCESS_MASK) == SUCCESS_MASK;
+ isSuccessCode = (notificationCode & SUCCESS_MASK) != 0;
// if Phase bit == 0, notification code can only be used after a successful
- isPreSuccessfulChallenge =
- (notificationCode & PRE_SUCCESSFUL_CHALLENGE_MASK)
- == PRE_SUCCESSFUL_CHALLENGE_MASK;
+ isPreSuccessfulChallenge = (notificationCode & PRE_SUCCESSFUL_CHALLENGE_MASK) != 0;
if (isSuccessCode && isPreSuccessfulChallenge) {
throw new EapSimAkaInvalidAttributeException("Invalid state specified");
@@ -1046,4 +1050,113 @@ public abstract class EapSimAkaAttribute {
byteBuffer.put(auts);
}
}
+
+ /**
+ * AtKdfInput represents the AT_KDF_INPUT attribute defined in RFC 5448#3.1
+ */
+ public static class AtKdfInput extends EapSimAkaAttribute {
+ public final byte[] networkName;
+
+ public AtKdfInput(int lengthInBytes, ByteBuffer byteBuffer)
+ throws EapSimAkaInvalidAttributeException {
+ super(EAP_AT_KDF_INPUT, lengthInBytes);
+
+ int networkNameLength = Short.toUnsignedInt(byteBuffer.getShort());
+ networkName = new byte[networkNameLength];
+ byteBuffer.get(networkName);
+
+ int bytesUsed = MIN_ATTR_LENGTH + networkNameLength;
+ consumePadding(bytesUsed, byteBuffer);
+ }
+
+ @VisibleForTesting
+ public AtKdfInput(int lengthInbytes, byte[] networkName)
+ throws EapSimAkaInvalidAttributeException {
+ super(EAP_AT_KDF_INPUT, lengthInbytes);
+
+ this.networkName = networkName;
+ }
+
+ @Override
+ public void encode(ByteBuffer byteBuffer) {
+ encodeAttributeHeader(byteBuffer);
+ byteBuffer.putShort((short) networkName.length);
+ byteBuffer.put(networkName);
+
+ int bytesUsed = MIN_ATTR_LENGTH + networkName.length;
+ addPadding(bytesUsed, byteBuffer);
+ }
+ }
+
+ /**
+ * AdKdf represents the AT_KDF attribute defined in RFC 5448#3.2
+ */
+ public static class AtKdf extends EapSimAkaAttribute {
+ private static final int ATTR_LENGTH = MIN_ATTR_LENGTH;
+
+ public final int kdf;
+
+ public AtKdf(int lengthInBytes, ByteBuffer buffer)
+ throws EapSimAkaInvalidAttributeException {
+ super(EAP_AT_KDF, lengthInBytes);
+
+ if (lengthInBytes != ATTR_LENGTH) {
+ throw new EapSimAkaInvalidAttributeException("AtKdf length must be 4B");
+ }
+
+ kdf = Short.toUnsignedInt(buffer.getShort());
+ }
+
+ @VisibleForTesting
+ public AtKdf(int kdf) throws EapSimAkaInvalidAttributeException {
+ super(EAP_AT_KDF, ATTR_LENGTH);
+
+ this.kdf = kdf;
+ }
+
+ @Override
+ public void encode(ByteBuffer byteBuffer) {
+ encodeAttributeHeader(byteBuffer);
+
+ byteBuffer.putShort((short) kdf);
+ }
+ }
+
+ /**
+ * AtBidding represents the AT_BIDDING attribute defined in RFC 5448#4
+ */
+ public static class AtBidding extends EapSimAkaAttribute {
+ private static final int ATTR_LENGTH = MIN_ATTR_LENGTH;
+ private static final int SUPPORTS_EAP_AKA_PRIME_MASK = 0x8000;
+
+ public final boolean doesServerSupportEapAkaPrime;
+
+ public AtBidding(int lengthInBytes, ByteBuffer buffer)
+ throws EapSimAkaInvalidAttributeException {
+ super(EAP_AT_BIDDING, lengthInBytes);
+
+ if (lengthInBytes != ATTR_LENGTH) {
+ throw new EapSimAkaInvalidAttributeException("AtBidding length must be 4B");
+ }
+
+ int serverFlag = Short.toUnsignedInt(buffer.getShort());
+ doesServerSupportEapAkaPrime = (serverFlag & SUPPORTS_EAP_AKA_PRIME_MASK) != 0;
+ }
+
+ @VisibleForTesting
+ public AtBidding(boolean doesServerSupportEapAkaPrime)
+ throws EapSimAkaInvalidAttributeException {
+ super(EAP_AT_BIDDING, ATTR_LENGTH);
+
+ this.doesServerSupportEapAkaPrime = doesServerSupportEapAkaPrime;
+ }
+
+ @Override
+ public void encode(ByteBuffer byteBuffer) {
+ encodeAttributeHeader(byteBuffer);
+
+ int flagToWrite = doesServerSupportEapAkaPrime ? SUPPORTS_EAP_AKA_PRIME_MASK : 0;
+ byteBuffer.putShort((short) flagToWrite);
+ }
+ }
}
diff --git a/src/java/com/android/ike/eap/message/simaka/EapSimAkaAttributeFactory.java b/src/java/com/android/ike/eap/message/simaka/EapSimAkaAttributeFactory.java
index 25a2459b..9a1ae7a1 100644
--- a/src/java/com/android/ike/eap/message/simaka/EapSimAkaAttributeFactory.java
+++ b/src/java/com/android/ike/eap/message/simaka/EapSimAkaAttributeFactory.java
@@ -68,17 +68,14 @@ public abstract class EapSimAkaAttributeFactory {
* @param lengthInBytes the length in bytes of the attribute to be decoded
* @param byteBuffer The ByteBuffer to parse the current attribute from
* @return The current EapSimAkaAttribute to be parsed, or EapSimAkaUnsupportedAttribute if the
- * given attributeType is skippable and unsupported
+ * given attributeType is skippable and unsupported
* @throws EapSimAkaInvalidAttributeException when a malformatted attribute is attempted to be
- * decoded
+ * decoded
* @throws EapSimAkaUnsupportedAttributeException when an unsupported, unskippable Attribute is
- * attempted to be decoded
+ * attempted to be decoded
*/
- protected EapSimAkaAttribute getAttribute(
- int attributeType,
- int lengthInBytes,
- ByteBuffer byteBuffer) throws EapSimAkaInvalidAttributeException,
- EapSimAkaUnsupportedAttributeException {
+ EapSimAkaAttribute getAttribute(int attributeType, int lengthInBytes, ByteBuffer byteBuffer)
+ throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
switch (attributeType) {
// TODO(b/139482157): define optional shared attributes
case EAP_AT_PERMANENT_ID_REQ:
diff --git a/src/java/com/android/ike/eap/statemachine/EapAkaMethodStateMachine.java b/src/java/com/android/ike/eap/statemachine/EapAkaMethodStateMachine.java
index 39328347..a0f1312a 100644
--- a/src/java/com/android/ike/eap/statemachine/EapAkaMethodStateMachine.java
+++ b/src/java/com/android/ike/eap/statemachine/EapAkaMethodStateMachine.java
@@ -99,6 +99,9 @@ import java.util.Set;
class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
private static final String TAG = EapAkaMethodStateMachine.class.getSimpleName();
+ // EAP-AKA identity prefix (RFC 4187#4.1.1.6)
+ private static final String AKA_IDENTITY_PREFIX = "0";
+
private final EapAkaTypeDataDecoder mEapAkaTypeDataDecoder;
EapAkaMethodStateMachine(Context context, byte[] eapIdentity, EapAkaConfig eapAkaConfig) {
@@ -130,6 +133,27 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
return EAP_TYPE_AKA;
}
+ protected DecodeResult<EapAkaTypeData> decode(byte[] typeData) {
+ return mEapAkaTypeDataDecoder.decode(typeData);
+ }
+
+ /**
+ * This exists so we can override the identity prefix in the EapAkaPrimeMethodStateMachine.
+ *
+ * @return the Identity prefix for this EAP method
+ */
+ protected String getIdentityPrefix() {
+ return AKA_IDENTITY_PREFIX;
+ }
+
+ protected ChallengeState buildChallengeState() {
+ return new ChallengeState();
+ }
+
+ protected ChallengeState buildChallengeState(byte[] identity) {
+ return new ChallengeState(identity);
+ }
+
protected class CreatedState extends EapMethodState {
private final String mTAG = CreatedState.class.getSimpleName();
@@ -139,13 +163,11 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
return result;
}
- DecodeResult<EapAkaTypeData> decodeResult =
- mEapAkaTypeDataDecoder.decode(message.eapData.eapTypeData);
+ DecodeResult<? extends EapAkaTypeData> decodeResult =
+ decode(message.eapData.eapTypeData);
if (!decodeResult.isSuccessfulDecode()) {
return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_AKA,
- decodeResult.atClientErrorCode);
+ message.eapIdentifier, getEapMethod(), decodeResult.atClientErrorCode);
}
EapAkaTypeData eapAkaTypeData = decodeResult.eapTypeData;
@@ -153,7 +175,7 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
case EAP_AKA_IDENTITY:
return transitionAndProcess(new IdentityState(), message);
case EAP_AKA_CHALLENGE:
- return transitionAndProcess(new ChallengeState(), message);
+ return transitionAndProcess(buildChallengeState(), message);
case EAP_AKA_NOTIFICATION:
return handleEapSimAkaNotification(
mTAG,
@@ -163,7 +185,7 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
default:
return buildClientErrorResponse(
message.eapIdentifier,
- EAP_TYPE_AKA,
+ getEapMethod(),
AtClientErrorCode.UNABLE_TO_PROCESS);
}
}
@@ -180,13 +202,11 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
return result;
}
- DecodeResult<EapAkaTypeData> decodeResult =
- mEapAkaTypeDataDecoder.decode(message.eapData.eapTypeData);
+ DecodeResult<? extends EapAkaTypeData> decodeResult =
+ decode(message.eapData.eapTypeData);
if (!decodeResult.isSuccessfulDecode()) {
return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_AKA,
- decodeResult.atClientErrorCode);
+ message.eapIdentifier, getEapMethod(), decodeResult.atClientErrorCode);
}
EapAkaTypeData eapAkaTypeData = decodeResult.eapTypeData;
@@ -194,7 +214,7 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
case EAP_AKA_IDENTITY:
break;
case EAP_AKA_CHALLENGE:
- return transitionAndProcess(new ChallengeState(mIdentity), message);
+ return transitionAndProcess(buildChallengeState(mIdentity), message);
case EAP_AKA_NOTIFICATION:
return handleEapSimAkaNotification(
mTAG,
@@ -204,7 +224,7 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
default:
return buildClientErrorResponse(
message.eapIdentifier,
- EAP_TYPE_AKA,
+ getEapMethod(),
AtClientErrorCode.UNABLE_TO_PROCESS);
}
@@ -223,7 +243,7 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
new EapSimAkaIdentityUnavailableException(
"IMSI for subId (" + mEapUiccConfig.subId + ") not available"));
}
- String identityString = "0" + imsi;
+ String identityString = getIdentityPrefix() + imsi;
mIdentity = identityString.getBytes(StandardCharsets.US_ASCII);
LOG.d(mTAG, "EAP-AKA/Identity=" + LOG.pii(identityString));
@@ -236,7 +256,7 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
}
return buildResponseMessage(
- EAP_TYPE_AKA,
+ getEapMethod(),
EAP_AKA_IDENTITY,
message.eapIdentifier,
Arrays.asList(atIdentity));
@@ -269,7 +289,7 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
private final String mTAG = ChallengeState.class.getSimpleName();
@VisibleForTesting boolean mHadSuccessfulChallenge = false;
- @VisibleForTesting final byte[] mIdentity;
+ @VisibleForTesting protected final byte[] mIdentity;
// IK and CK lengths defined as 16B (RFC 4187#1)
private final int mIkLenBytes = 16;
@@ -311,13 +331,11 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
+ ", received " + message.eapData.eapType));
}
- DecodeResult<EapAkaTypeData> decodeResult =
- mEapAkaTypeDataDecoder.decode(message.eapData.eapTypeData);
+ DecodeResult<? extends EapAkaTypeData> decodeResult =
+ decode(message.eapData.eapTypeData);
if (!decodeResult.isSuccessfulDecode()) {
return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_AKA,
- decodeResult.atClientErrorCode);
+ message.eapIdentifier, getEapMethod(), decodeResult.atClientErrorCode);
}
EapAkaTypeData eapAkaTypeData = decodeResult.eapTypeData;
@@ -333,18 +351,21 @@ class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
default:
return buildClientErrorResponse(
message.eapIdentifier,
- EAP_TYPE_AKA,
+ getEapMethod(),
AtClientErrorCode.UNABLE_TO_PROCESS);
}
if (!isValidChallengeAttributes(eapAkaTypeData)) {
LOG.e(mTAG, "Invalid attributes: " + eapAkaTypeData.attributeMap.keySet());
return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_AKA,
- AtClientErrorCode.UNABLE_TO_PROCESS);
+ message.eapIdentifier, getEapMethod(), AtClientErrorCode.UNABLE_TO_PROCESS);
}
+ return handleChallengeAuthentication(message, eapAkaTypeData);
+ }
+
+ protected EapResult handleChallengeAuthentication(
+ EapMessage message, EapAkaTypeData eapAkaTypeData) {
RandChallengeResult result;
try {
result = getRandChallengeResult(eapAkaTypeData);
diff --git a/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachine.java b/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachine.java
new file mode 100644
index 00000000..38eafb38
--- /dev/null
+++ b/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachine.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.statemachine;
+
+import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME;
+import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_CLIENT_ERROR;
+
+import android.content.Context;
+
+import com.android.ike.eap.EapResult;
+import com.android.ike.eap.EapSessionConfig.EapAkaPrimeConfig;
+import com.android.ike.eap.message.EapData.EapMethod;
+import com.android.ike.eap.message.EapMessage;
+import com.android.ike.eap.message.simaka.EapAkaPrimeTypeData;
+import com.android.ike.eap.message.simaka.EapAkaPrimeTypeData.EapAkaPrimeTypeDataDecoder;
+import com.android.ike.eap.message.simaka.EapAkaTypeData;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
+import com.android.ike.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * EapAkaPrimeMethodStateMachine represents the valid paths possible for the EAP-AKA' protocol.
+ *
+ * <p>EAP-AKA' sessions will always follow the path:
+ *
+ * Created --+--> Identity --+--> Challenge --> Final
+ * | |
+ * +---------------+
+ *
+ * <p>Note: If the EAP-Request/AKA'-Challenge message contains an AUTN with an invalid sequence
+ * number, the peer will indicate a synchronization failure to the server and a new challenge will
+ * be attempted.
+ *
+ * <p>Note: EAP-Request/Notification messages can be received at any point in the above state
+ * machine At most one EAP-AKA'/Notification message is allowed per EAP-AKA' session.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4187">RFC 4187, Extensible Authentication Protocol
+ * for Authentication and Key Agreement (EAP-AKA)</a>
+ * @see <a href="https://tools.ietf.org/html/rfc5448">RFC 5448, Improved Extensible Authentication
+ * Protocol Method for 3rd Generation Authentication and Key Agreement (EAP-AKA')</a>
+ */
+public class EapAkaPrimeMethodStateMachine extends EapAkaMethodStateMachine {
+ // EAP-AKA' identity prefix (RFC 5448#3)
+ private static final String AKA_PRIME_IDENTITY_PREFIX = "6";
+
+ private final EapAkaPrimeTypeDataDecoder mEapAkaPrimeTypeDataDecoder;
+
+ EapAkaPrimeMethodStateMachine(
+ Context context, byte[] eapIdentity, EapAkaPrimeConfig eapAkaPrimeConfig) {
+ this(
+ context,
+ eapIdentity,
+ eapAkaPrimeConfig,
+ EapAkaPrimeTypeData.getEapAkaPrimeTypeDataDecoder());
+ }
+
+ @VisibleForTesting
+ protected EapAkaPrimeMethodStateMachine(
+ Context context,
+ byte[] eapIdentity,
+ EapAkaPrimeConfig eapAkaPrimeConfig,
+ EapAkaPrimeTypeDataDecoder eapAkaPrimeTypeDataDecoder) {
+ super(context, eapIdentity, eapAkaPrimeConfig);
+ mEapAkaPrimeTypeDataDecoder = eapAkaPrimeTypeDataDecoder;
+
+ transitionTo(new CreatedState());
+ }
+
+ @Override
+ @EapMethod
+ int getEapMethod() {
+ return EAP_TYPE_AKA_PRIME;
+ }
+
+ @Override
+ protected DecodeResult<EapAkaTypeData> decode(byte[] typeData) {
+ return mEapAkaPrimeTypeDataDecoder.decode(typeData);
+ }
+
+ @Override
+ protected String getIdentityPrefix() {
+ return AKA_PRIME_IDENTITY_PREFIX;
+ }
+
+ @Override
+ protected ChallengeState buildChallengeState() {
+ return new ChallengeState();
+ }
+
+ @Override
+ protected ChallengeState buildChallengeState(byte[] identity) {
+ return new ChallengeState(identity);
+ }
+
+ protected class ChallengeState extends EapAkaMethodStateMachine.ChallengeState {
+ ChallengeState() {
+ super();
+ }
+
+ ChallengeState(byte[] identity) {
+ super(identity);
+ }
+
+ @Override
+ protected EapResult handleChallengeAuthentication(
+ EapMessage message, EapAkaTypeData eapAkaTypeData) {
+ return null;
+ }
+ }
+
+ EapAkaPrimeTypeData getEapSimAkaTypeData(AtClientErrorCode clientErrorCode) {
+ return new EapAkaPrimeTypeData(EAP_AKA_CLIENT_ERROR, Arrays.asList(clientErrorCode));
+ }
+
+ EapAkaPrimeTypeData getEapSimAkaTypeData(int eapSubtype, List<EapSimAkaAttribute> attributes) {
+ return new EapAkaPrimeTypeData(eapSubtype, attributes);
+ }
+}
diff --git a/src/java/com/android/ike/eap/statemachine/EapStateMachine.java b/src/java/com/android/ike/eap/statemachine/EapStateMachine.java
index a59b7919..e1d793c1 100644
--- a/src/java/com/android/ike/eap/statemachine/EapStateMachine.java
+++ b/src/java/com/android/ike/eap/statemachine/EapStateMachine.java
@@ -21,6 +21,7 @@ import static com.android.ike.eap.message.EapData.EAP_IDENTITY;
import static com.android.ike.eap.message.EapData.EAP_NAK;
import static com.android.ike.eap.message.EapData.EAP_NOTIFICATION;
import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA;
+import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME;
import static com.android.ike.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
import static com.android.ike.eap.message.EapData.EAP_TYPE_SIM;
import static com.android.ike.eap.message.EapData.EAP_TYPE_STRING;
@@ -41,6 +42,7 @@ import com.android.ike.eap.EapResult.EapResponse;
import com.android.ike.eap.EapResult.EapSuccess;
import com.android.ike.eap.EapSessionConfig;
import com.android.ike.eap.EapSessionConfig.EapAkaConfig;
+import com.android.ike.eap.EapSessionConfig.EapAkaPrimeConfig;
import com.android.ike.eap.EapSessionConfig.EapMethodConfig;
import com.android.ike.eap.EapSessionConfig.EapMsChapV2Config;
import com.android.ike.eap.EapSessionConfig.EapSimConfig;
@@ -317,8 +319,6 @@ public class EapStateMachine extends SimpleStateMachine<byte[], EapResult> {
}
switch (eapType) {
- // TODO(b/133878093): implement EapAkaPrimeStateMachine
-
case EAP_TYPE_SIM:
EapSimConfig eapSimConfig = (EapSimConfig) eapMethodConfig;
return new EapSimMethodStateMachine(
@@ -327,6 +327,10 @@ public class EapStateMachine extends SimpleStateMachine<byte[], EapResult> {
EapAkaConfig eapAkaConfig = (EapAkaConfig) eapMethodConfig;
return new EapAkaMethodStateMachine(
mContext, mEapSessionConfig.eapIdentity, eapAkaConfig);
+ case EAP_TYPE_AKA_PRIME:
+ EapAkaPrimeConfig eapAkaPrimeConfig = (EapAkaPrimeConfig) eapMethodConfig;
+ return new EapAkaPrimeMethodStateMachine(
+ mContext, mEapSessionConfig.eapIdentity, eapAkaPrimeConfig);
case EAP_TYPE_MSCHAP_V2:
EapMsChapV2Config eapMsChapV2Config = (EapMsChapV2Config) eapMethodConfig;
return new EapMsChapV2MethodStateMachine(eapMsChapV2Config, mSecureRandom);
diff --git a/src/java/com/android/ike/ikev2/IkeSessionOptions.java b/src/java/com/android/ike/ikev2/IkeSessionOptions.java
index 964e89e9..173c3ea7 100644
--- a/src/java/com/android/ike/ikev2/IkeSessionOptions.java
+++ b/src/java/com/android/ike/ikev2/IkeSessionOptions.java
@@ -177,10 +177,11 @@ public final class IkeSessionOptions {
/** This class can be used to incrementally construct a IkeSessionOptions. */
public static final class Builder {
- private final InetAddress mServerAddress;
- private final UdpEncapsulationSocket mUdpEncapSocket;
private final List<IkeSaProposal> mSaProposalList = new LinkedList<>();
+ private InetAddress mServerAddress;
+ private UdpEncapsulationSocket mUdpEncapSocket;
+
private IkeIdentification mLocalIdentification;
private IkeIdentification mRemoteIdentification;
@@ -190,16 +191,27 @@ public final class IkeSessionOptions {
private boolean mIsIkeFragmentationSupported = false;
/**
- * Returns a new Builder for an IkeSessionOptions.
+ * Sets server address
*
* @param serverAddress IP address of remote IKE server.
+ * @return Builder this, to facilitate chaining.
+ */
+ public Builder setServerAddress(@NonNull InetAddress serverAddress) {
+ mServerAddress = serverAddress;
+ return this;
+ }
+
+ /**
+ * Sets UDP-Encapsulated socket
+ *
* @param udpEncapsulationSocket {@link IpSecManager.UdpEncapsulationSocket} for sending and
* receiving IKE message.
- * @return Builder for an IkeSessionOptions.
+ * @return Builder this, to facilitate chaining.
*/
- public Builder(InetAddress serverAddress, UdpEncapsulationSocket udpEncapsulationSocket) {
- mServerAddress = serverAddress;
+ public Builder setUdpEncapsulationSocket(
+ @NonNull UdpEncapsulationSocket udpEncapsulationSocket) {
mUdpEncapSocket = udpEncapsulationSocket;
+ return this;
}
/**
@@ -302,12 +314,13 @@ public final class IkeSessionOptions {
if (mSaProposalList.isEmpty()) {
throw new IllegalArgumentException("IKE SA proposal not found");
}
- if (mLocalIdentification == null
+ if (mServerAddress == null
+ || mUdpEncapSocket == null
+ || mLocalIdentification == null
|| mRemoteIdentification == null
|| mLocalAuthConfig == null
|| mRemoteAuthConfig == null) {
- throw new IllegalArgumentException(
- "IKE identification or IKE authentication method is not set.");
+ throw new IllegalArgumentException("Necessary parameter missing.");
}
return new IkeSessionOptions(
diff --git a/tests/iketests/src/java/com/android/ike/eap/EapSessionConfigTest.java b/tests/iketests/src/java/com/android/ike/eap/EapSessionConfigTest.java
index 1591cbb6..ffed33fb 100644
--- a/tests/iketests/src/java/com/android/ike/eap/EapSessionConfigTest.java
+++ b/tests/iketests/src/java/com/android/ike/eap/EapSessionConfigTest.java
@@ -20,23 +20,31 @@ import static android.telephony.TelephonyManager.APPTYPE_USIM;
import static com.android.ike.eap.EapSessionConfig.DEFAULT_IDENTITY;
import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA;
+import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME;
import static com.android.ike.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
import static com.android.ike.eap.message.EapData.EAP_TYPE_SIM;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.android.ike.eap.EapSessionConfig.EapAkaConfig;
+import com.android.ike.eap.EapSessionConfig.EapAkaPrimeConfig;
import com.android.ike.eap.EapSessionConfig.EapMethodConfig;
import com.android.ike.eap.EapSessionConfig.EapMsChapV2Config;
import com.android.ike.eap.EapSessionConfig.EapSimConfig;
import org.junit.Test;
+import java.nio.charset.StandardCharsets;
+
public class EapSessionConfigTest {
- private static final byte[] EAP_IDENTITY = "test@android.net".getBytes();
+ private static final byte[] EAP_IDENTITY =
+ "test@android.net".getBytes(StandardCharsets.US_ASCII);
private static final int SUB_ID = 1;
+ private static final String NETWORK_NAME = "android.net";
+ private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true;
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
@@ -70,6 +78,23 @@ public class EapSessionConfigTest {
}
@Test
+ public void testBuildEapAkaPrime() {
+ EapSessionConfig result =
+ new EapSessionConfig.Builder()
+ .setEapAkaPrimeConfig(
+ SUB_ID, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES)
+ .build();
+
+ assertEquals(DEFAULT_IDENTITY, result.eapIdentity);
+ EapMethodConfig eapMethodConfig = result.eapConfigs.get(EAP_TYPE_AKA_PRIME);
+ EapAkaPrimeConfig eapAkaPrimeConfig = (EapAkaPrimeConfig) eapMethodConfig;
+ assertEquals(SUB_ID, eapAkaPrimeConfig.subId);
+ assertEquals(APPTYPE_USIM, eapAkaPrimeConfig.apptype);
+ assertEquals(NETWORK_NAME, eapAkaPrimeConfig.networkName);
+ assertTrue(eapAkaPrimeConfig.allowMismatchedNetworkNames);
+ }
+
+ @Test
public void testBuildEapMsChapV2() {
EapSessionConfig result =
new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build();
diff --git a/tests/iketests/src/java/com/android/ike/eap/message/EapTestMessageDefinitions.java b/tests/iketests/src/java/com/android/ike/eap/message/EapTestMessageDefinitions.java
index 2e937332..3ddbe549 100644
--- a/tests/iketests/src/java/com/android/ike/eap/message/EapTestMessageDefinitions.java
+++ b/tests/iketests/src/java/com/android/ike/eap/message/EapTestMessageDefinitions.java
@@ -307,4 +307,17 @@ public class EapTestMessageDefinitions {
public static final byte[] EAP_MSCHAP_V2_FAILURE_RESPONSE =
hexStringToByteArray("02" + ID + "0006" // EAP-Response | ID | length in bytes
+ "1A04"); // EAP-MSCHAPv2 | Failure
+
+ public static final byte[] EAP_AKA_PRIME_REQUEST =
+ hexStringToByteArray("01" + ID + "000832050000");
+ public static final byte[] EAP_AKA_PRIME_CLIENT_ERROR_UNABLE_TO_PROCESS =
+ hexStringToByteArray("02" + ID + "000C320E000016010000");
+ public static final String EAP_AKA_PRIME_IDENTITY = "36313233343536373839303132333435";
+ public static final byte[] EAP_AKA_PRIME_IDENTITY_BYTES =
+ hexStringToByteArray(EAP_AKA_PRIME_IDENTITY);
+ public static final byte[] EAP_AKA_PRIME_IDENTITY_RESPONSE =
+ hexStringToByteArray(
+ "02" + ID + "001C" // EAP-Response | ID | length in bytes
+ + "32050000" // EAP-AKA | Identity | 2B padding
+ + "0E050010" + EAP_AKA_PRIME_IDENTITY); // AT_IDENTITY ("6" + IMSI)
}
diff --git a/tests/iketests/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeTypeDataTest.java b/tests/iketests/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeTypeDataTest.java
new file mode 100644
index 00000000..36066f1e
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/message/simaka/EapAkaPrimeTypeDataTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.message.simaka;
+
+import static com.android.ike.TestUtils.hexStringToByteArray;
+import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN;
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF;
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF_INPUT;
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF_INPUT;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.KDF_VERSION;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.NETWORK_NAME_BYTES;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.NETWORK_NAME_HEX;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.ike.eap.message.simaka.EapAkaPrimeTypeData.EapAkaPrimeTypeDataDecoder;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtAutn;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtKdf;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtKdfInput;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtMac;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
+import com.android.ike.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+
+public class EapAkaPrimeTypeDataTest {
+ private static final String RAND = "7A1FCDC0034BA1227E7B9FCEAFD47D53";
+ private static final byte[] RAND_BYTES = hexStringToByteArray(RAND);
+ private static final String AUTN = "000102030405060708090A0B0C0D0E0F";
+ private static final byte[] AUTN_BYTES = hexStringToByteArray(AUTN);
+ private static final String MAC = "95FEB9E70427F34B4FAC8F2C7A65A302";
+ private static final byte[] MAC_BYTES = hexStringToByteArray(MAC);
+ private static final byte[] EAP_AKA_PRIME_CHALLENGE_REQUEST =
+ hexStringToByteArray(
+ "010000" // Challenge | 2B padding
+ + "01050000" + RAND // AT_RAND attribute
+ + "02050000" + AUTN // AT_AUTN attribute
+ + "1704000B" + NETWORK_NAME_HEX + "00" // AT_KDF_INPUT
+ + "18010001" // AT_KDF
+ + "0B050000" + MAC); // AT_MAC attribute
+ private static final byte[] EAP_AKA_PRIME_MULTIPLE_AT_KDF =
+ hexStringToByteArray(
+ "010000" // Challenge | 2B padding
+ + "01050000" + RAND // AT_RAND attribute
+ + "02050000" + AUTN // AT_AUTN attribute
+ + "1704000B" + NETWORK_NAME_HEX + "00" // AT_KDF_INPUT
+ + "18010001" // AT_KDF
+ + "18010002" // AT_KDF
+ + "0B050000" + MAC); // AT_MAC attribute
+
+ private EapAkaPrimeTypeDataDecoder mTypeDataDecoder;
+
+ @Before
+ public void setUp() {
+ mTypeDataDecoder = EapAkaPrimeTypeData.getEapAkaPrimeTypeDataDecoder();
+ }
+
+ @Test
+ public void testDecode() {
+ DecodeResult<EapAkaTypeData> result =
+ mTypeDataDecoder.decode(EAP_AKA_PRIME_CHALLENGE_REQUEST);
+
+ assertTrue(result.isSuccessfulDecode());
+ EapAkaPrimeTypeData eapAkaPrimeTypeData = (EapAkaPrimeTypeData) result.eapTypeData;
+ assertEquals(EAP_AKA_CHALLENGE, eapAkaPrimeTypeData.eapSubtype);
+
+ // also check Map entries (needs to match input order)
+ Iterator<Entry<Integer, EapSimAkaAttribute>> itr =
+ eapAkaPrimeTypeData.attributeMap.entrySet().iterator();
+ Entry<Integer, EapSimAkaAttribute> entry = itr.next();
+ assertEquals(EAP_AT_RAND, (int) entry.getKey());
+ assertArrayEquals(RAND_BYTES, ((AtRandAka) entry.getValue()).rand);
+
+ entry = itr.next();
+ assertEquals(EAP_AT_AUTN, (int) entry.getKey());
+ assertArrayEquals(AUTN_BYTES, ((AtAutn) entry.getValue()).autn);
+
+ entry = itr.next();
+ assertEquals(EAP_AT_KDF_INPUT, (int) entry.getKey());
+ assertArrayEquals(NETWORK_NAME_BYTES, ((AtKdfInput) entry.getValue()).networkName);
+
+ entry = itr.next();
+ assertEquals(EAP_AT_KDF, (int) entry.getKey());
+ assertEquals(KDF_VERSION, ((AtKdf) entry.getValue()).kdf);
+
+ entry = itr.next();
+ assertEquals(EAP_AT_MAC, (int) entry.getKey());
+ assertArrayEquals(MAC_BYTES, ((AtMac) entry.getValue()).mac);
+
+ assertFalse(itr.hasNext());
+ }
+
+ @Test
+ public void testDecodeMultipleAtKdfAttributes() {
+ DecodeResult<EapAkaTypeData> result =
+ mTypeDataDecoder.decode(EAP_AKA_PRIME_MULTIPLE_AT_KDF);
+
+ assertFalse(result.isSuccessfulDecode());
+ assertEquals(AtClientErrorCode.UNABLE_TO_PROCESS, result.atClientErrorCode);
+ }
+
+ @Test
+ public void testEncode() throws Exception {
+ LinkedHashMap<Integer, EapSimAkaAttribute> attributes = new LinkedHashMap<>();
+ attributes.put(EAP_AT_RAND, new AtRandAka(RAND_BYTES));
+ attributes.put(EAP_AT_AUTN, new AtAutn(AUTN_BYTES));
+ attributes.put(EAP_AT_KDF_INPUT, new AtKdfInput(AT_KDF_INPUT.length, NETWORK_NAME_BYTES));
+ attributes.put(EAP_AT_KDF, new AtKdf(KDF_VERSION));
+ attributes.put(EAP_AT_MAC, new AtMac(MAC_BYTES));
+ EapAkaPrimeTypeData eapAkaPrimeTypeData =
+ new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, attributes);
+
+ byte[] result = eapAkaPrimeTypeData.encode();
+ assertArrayEquals(EAP_AKA_PRIME_CHALLENGE_REQUEST, result);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtBiddingTest.java b/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtBiddingTest.java
new file mode 100644
index 00000000..3e6374e8
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtBiddingTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.message.simaka.attributes;
+
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_BIDDING;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_BIDDING_INVALID_LENGTH;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_BIDDING_SUPPORTS_AKA_PRIME;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.ike.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
+import com.android.ike.eap.message.simaka.EapAkaAttributeFactory;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtBidding;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public class AtBiddingTest {
+ private EapAkaAttributeFactory mAttributeFactory;
+
+ @Before
+ public void setUp() {
+ mAttributeFactory = EapAkaAttributeFactory.getInstance();
+ }
+
+ @Test
+ public void testDecodeServerSupportsAkaPrime() throws Exception {
+ ByteBuffer input = ByteBuffer.wrap(AT_BIDDING_SUPPORTS_AKA_PRIME);
+ EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
+
+ assertFalse(input.hasRemaining());
+ AtBidding atBidding = (AtBidding) result;
+ assertEquals(EAP_AT_BIDDING, atBidding.attributeType);
+ assertEquals(AT_BIDDING_SUPPORTS_AKA_PRIME.length, atBidding.lengthInBytes);
+ assertTrue(atBidding.doesServerSupportEapAkaPrime);
+ }
+
+ @Test
+ public void testDecodeDoesNotSupportAkaPrime() throws Exception {
+ ByteBuffer input = ByteBuffer.wrap(AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME);
+ EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
+
+ assertFalse(input.hasRemaining());
+ AtBidding atBidding = (AtBidding) result;
+ assertEquals(EAP_AT_BIDDING, atBidding.attributeType);
+ assertEquals(AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME.length, atBidding.lengthInBytes);
+ assertFalse(atBidding.doesServerSupportEapAkaPrime);
+ }
+
+ @Test
+ public void testDecodeInvalidLength() throws Exception {
+ ByteBuffer input = ByteBuffer.wrap(AT_BIDDING_INVALID_LENGTH);
+ try {
+ mAttributeFactory.getAttribute(input);
+ fail("Expected EapSimAkaInvalidAttributeException for invalid length");
+ } catch (EapSimAkaInvalidAttributeException expected) {
+ }
+ }
+
+ @Test
+ public void testEncodeServerSupportsAkaPrime() throws Exception {
+ AtBidding atBidding = new AtBidding(true);
+
+ ByteBuffer result = ByteBuffer.allocate(AT_BIDDING_SUPPORTS_AKA_PRIME.length);
+ atBidding.encode(result);
+ assertArrayEquals(AT_BIDDING_SUPPORTS_AKA_PRIME, result.array());
+ }
+
+ @Test
+ public void testEncodeDoesNotSupportAkaPrime() throws Exception {
+ AtBidding atBidding = new AtBidding(false);
+
+ ByteBuffer result = ByteBuffer.allocate(AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME.length);
+ atBidding.encode(result);
+ assertArrayEquals(AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME, result.array());
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtKdfInputTest.java b/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtKdfInputTest.java
new file mode 100644
index 00000000..dc13f087
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtKdfInputTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.message.simaka.attributes;
+
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF_INPUT;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF_INPUT;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF_INPUT_EMPTY_NETWORK_NAME;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.NETWORK_NAME_BYTES;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.android.ike.eap.message.simaka.EapAkaPrimeAttributeFactory;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtKdfInput;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public class AtKdfInputTest {
+ private EapAkaPrimeAttributeFactory mAttributeFactory;
+
+ @Before
+ public void setUp() {
+ mAttributeFactory = EapAkaPrimeAttributeFactory.getInstance();
+ }
+
+ @Test
+ public void testDecode() throws Exception {
+ ByteBuffer input = ByteBuffer.wrap(AT_KDF_INPUT);
+ EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
+
+ assertFalse(input.hasRemaining());
+ AtKdfInput atKdfInput = (AtKdfInput) result;
+ assertEquals(EAP_AT_KDF_INPUT, atKdfInput.attributeType);
+ assertEquals(AT_KDF_INPUT.length, atKdfInput.lengthInBytes);
+ assertArrayEquals(NETWORK_NAME_BYTES, atKdfInput.networkName);
+ }
+
+ @Test
+ public void testDecodeEmptyNetworkName() throws Exception {
+ ByteBuffer input = ByteBuffer.wrap(AT_KDF_INPUT_EMPTY_NETWORK_NAME);
+ EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
+
+ assertFalse(input.hasRemaining());
+ AtKdfInput atKdfInput = (AtKdfInput) result;
+ assertEquals(EAP_AT_KDF_INPUT, atKdfInput.attributeType);
+ assertEquals(AT_KDF_INPUT_EMPTY_NETWORK_NAME.length, atKdfInput.lengthInBytes);
+ assertArrayEquals(new byte[0], atKdfInput.networkName);
+ }
+
+ @Test
+ public void testEncode() throws Exception {
+ AtKdfInput atKdfInput = new AtKdfInput(AT_KDF_INPUT.length, NETWORK_NAME_BYTES);
+ ByteBuffer result = ByteBuffer.allocate(AT_KDF_INPUT.length);
+
+ atKdfInput.encode(result);
+ assertArrayEquals(AT_KDF_INPUT, result.array());
+ assertFalse(result.hasRemaining());
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtKdfTest.java b/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtKdfTest.java
new file mode 100644
index 00000000..0a1209c8
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/AtKdfTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.message.simaka.attributes;
+
+import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF_INVALID_LENGTH;
+import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefinitions.KDF_VERSION;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import com.android.ike.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
+import com.android.ike.eap.message.simaka.EapAkaPrimeAttributeFactory;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtKdf;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public class AtKdfTest {
+ private EapAkaPrimeAttributeFactory mAttributeFactory;
+
+ @Before
+ public void setUp() {
+ mAttributeFactory = EapAkaPrimeAttributeFactory.getInstance();
+ }
+
+ @Test
+ public void testDecode() throws Exception {
+ ByteBuffer input = ByteBuffer.wrap(AT_KDF);
+ EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
+
+ assertFalse(input.hasRemaining());
+ AtKdf atKdf = (AtKdf) result;
+ assertEquals(EAP_AT_KDF, atKdf.attributeType);
+ assertEquals(AT_KDF.length, atKdf.lengthInBytes);
+ assertEquals(KDF_VERSION, atKdf.kdf);
+ }
+
+ @Test
+ public void testDecodeInvalidLength() throws Exception {
+ ByteBuffer input = ByteBuffer.wrap(AT_KDF_INVALID_LENGTH);
+ try {
+ mAttributeFactory.getAttribute(input);
+ fail("Expected EapSimAkaInvalidAttributeException for invalid length");
+ } catch (EapSimAkaInvalidAttributeException expected) {
+ }
+ }
+
+ @Test
+ public void testEncode() throws Exception {
+ AtKdf atKdf = new AtKdf(KDF_VERSION);
+ ByteBuffer result = ByteBuffer.allocate(AT_KDF.length);
+
+ atKdf.encode(result);
+ assertArrayEquals(AT_KDF, result.array());
+ assertFalse(result.hasRemaining());
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/EapTestAttributeDefinitions.java b/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/EapTestAttributeDefinitions.java
index c17c51e8..01a7da1d 100644
--- a/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/EapTestAttributeDefinitions.java
+++ b/tests/iketests/src/java/com/android/ike/eap/message/simaka/attributes/EapTestAttributeDefinitions.java
@@ -73,6 +73,18 @@ public class EapTestAttributeDefinitions {
public static final String AUTS = "112233445566778899AABBCCDDEE";
public static final byte[] AUTS_BYTES = hexStringToByteArray(AUTS);
public static final byte[] AT_AUTS = hexStringToByteArray("0404" + AUTS);
+ public static final byte[] AT_BIDDING_SUPPORTS_AKA_PRIME = hexStringToByteArray("88018000");
+ public static final byte[] AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME =
+ hexStringToByteArray("88010000");
+
+ // Network Name = "android.net"
+ public static final String NETWORK_NAME_HEX = "616E64726F69642E6E6574";
+ public static final byte[] NETWORK_NAME_BYTES = hexStringToByteArray(NETWORK_NAME_HEX);
+ public static final byte[] AT_KDF_INPUT =
+ hexStringToByteArray("1704000B" + NETWORK_NAME_HEX + "00");
+ public static final byte[] AT_KDF_INPUT_EMPTY_NETWORK_NAME = hexStringToByteArray("17010000");
+ public static final int KDF_VERSION = 1;
+ public static final byte[] AT_KDF = hexStringToByteArray("18010001");
public static final byte[] AT_VERSION_LIST_INVALID_LENGTH = hexStringToByteArray("0F020003");
public static final byte[] AT_SELECTED_VERSION_INVALID_LENGTH =
@@ -103,4 +115,6 @@ public class EapTestAttributeDefinitions {
public static final byte[] AT_RES_LONG_RES =
hexStringToByteArray("0306008800112233445566778899AABBCCDDEEFF11000000");
public static final byte[] AT_AUTS_INVALID_LENGTH = hexStringToByteArray("03010000");
+ public static final byte[] AT_KDF_INVALID_LENGTH = hexStringToByteArray("18020001");
+ public static final byte[] AT_BIDDING_INVALID_LENGTH = hexStringToByteArray("88020000");
}
diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaIdentityStateTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaIdentityStateTest.java
index df09fbd4..dcfeb0f1 100644
--- a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaIdentityStateTest.java
+++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaIdentityStateTest.java
@@ -157,6 +157,5 @@ public class EapAkaIdentityStateTest extends EapAkaStateTest {
// decoded in IdentityState and ChallengeState
verify(mMockEapAkaTypeDataDecoder, times(2)).decode(DUMMY_EAP_TYPE_DATA);
verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
-
}
}
diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeChallengeStateTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeChallengeStateTest.java
new file mode 100644
index 00000000..8eac86b9
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeChallengeStateTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.statemachine;
+
+import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME;
+import static com.android.ike.eap.message.EapMessage.EAP_CODE_REQUEST;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_IDENTITY_BYTES;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_IDENTITY_RESPONSE;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.ID_INT;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.IMSI;
+import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
+import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.android.ike.eap.EapResult.EapResponse;
+import com.android.ike.eap.message.EapData;
+import com.android.ike.eap.message.EapMessage;
+import com.android.ike.eap.message.simaka.EapAkaPrimeTypeData;
+import com.android.ike.eap.message.simaka.EapAkaTypeData;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
+import com.android.ike.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
+import com.android.ike.eap.statemachine.EapAkaPrimeMethodStateMachine.ChallengeState;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class EapAkaPrimeChallengeStateTest extends EapAkaPrimeStateTest {
+ @Before
+ public void setUp() {
+ super.setUp();
+
+ mStateMachine.transitionTo(mStateMachine.new ChallengeState());
+ }
+
+ @Test
+ public void testTransitionWithEapIdentity() throws Exception {
+ mStateMachine.transitionTo(mStateMachine.new CreatedState());
+
+ EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
+ EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
+
+ DecodeResult<EapAkaTypeData> decodeResult =
+ new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, new ArrayList<>()));
+ when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
+
+ mStateMachine.process(eapMessage);
+
+ ChallengeState challengeState = (ChallengeState) mStateMachine.getState();
+ assertArrayEquals(EAP_IDENTITY_BYTES, challengeState.mIdentity);
+
+ // decode() is called in CreatedState and ChallengeState
+ verify(mMockTypeDataDecoder, times(2)).decode(eq(DUMMY_EAP_TYPE_DATA));
+ }
+
+ @Test
+ public void testTransitionWithEapAkaPrimeIdentity() throws Exception {
+ mStateMachine.transitionTo(mStateMachine.new CreatedState());
+
+ // Process AKA' Identity Request
+ EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
+ EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
+
+ DecodeResult<EapAkaTypeData> decodeResult =
+ new DecodeResult<>(
+ new EapAkaPrimeTypeData(EAP_AKA_IDENTITY, Arrays.asList(new AtAnyIdReq())));
+ when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
+ when(mMockTelephonyManager.getSubscriberId()).thenReturn(IMSI);
+
+ EapResponse eapResponse = (EapResponse) mStateMachine.process(eapMessage);
+ assertArrayEquals(EAP_AKA_PRIME_IDENTITY_RESPONSE, eapResponse.packet);
+
+ // decode() is called in CreatedState and IdentityState
+ verify(mMockTypeDataDecoder, times(2)).decode(eq(DUMMY_EAP_TYPE_DATA));
+ verify(mMockTelephonyManager).getSubscriberId();
+
+ // Process AKA' Challenge Request
+ decodeResult =
+ new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, new ArrayList<>()));
+ when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
+
+ mStateMachine.process(eapMessage);
+
+ ChallengeState challengeState = (ChallengeState) mStateMachine.getState();
+ assertArrayEquals(EAP_AKA_PRIME_IDENTITY_BYTES, challengeState.mIdentity);
+
+ // decode() called again in IdentityState and ChallengeState
+ verify(mMockTypeDataDecoder, times(4)).decode(eq(DUMMY_EAP_TYPE_DATA));
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeCreatedStateTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeCreatedStateTest.java
new file mode 100644
index 00000000..8664cdab
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeCreatedStateTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.statemachine;
+
+import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME;
+import static com.android.ike.eap.message.EapMessage.EAP_CODE_REQUEST;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.ID_INT;
+import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
+import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import com.android.ike.eap.message.EapData;
+import com.android.ike.eap.message.EapMessage;
+import com.android.ike.eap.message.simaka.EapAkaPrimeTypeData;
+import com.android.ike.eap.message.simaka.EapAkaTypeData;
+import com.android.ike.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
+import com.android.ike.eap.statemachine.EapAkaPrimeMethodStateMachine.ChallengeState;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+public class EapAkaPrimeCreatedStateTest extends EapAkaPrimeStateTest {
+ @Test
+ public void testProcessTransitionToIdentityState() throws Exception {
+ EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
+ EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
+
+ // Don't actually need any attributes in the attributeMap, since we only care about the
+ // state transition here.
+ DecodeResult<EapAkaTypeData> decodeResult =
+ new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_IDENTITY, new ArrayList<>()));
+ when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
+
+ mStateMachine.process(eapMessage);
+
+ assertTrue(mStateMachine.getState() instanceof EapAkaMethodStateMachine.IdentityState);
+
+ // decoded in CreatedState and IdentityState
+ verify(mMockTypeDataDecoder, times(2)).decode(eq(DUMMY_EAP_TYPE_DATA));
+ verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
+ }
+
+ @Test
+ public void testProcessTransitionToChallengeState() throws Exception {
+ EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
+ EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
+
+ // Don't actually need any attributes in the attributeMap, since we only care about the
+ // state transition here.
+ DecodeResult<EapAkaTypeData> decodeResult =
+ new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, new ArrayList<>()));
+ when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
+
+ mStateMachine.process(eapMessage);
+
+ ChallengeState challengeState = (ChallengeState) mStateMachine.getState();
+ assertArrayEquals(EAP_IDENTITY_BYTES, challengeState.mIdentity);
+
+ // decoded in CreatedState and ChallengeState
+ verify(mMockTypeDataDecoder, times(2)).decode(DUMMY_EAP_TYPE_DATA);
+ verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeIdentityStateTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeIdentityStateTest.java
new file mode 100644
index 00000000..0ce5a45a
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeIdentityStateTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.statemachine;
+
+import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME;
+import static com.android.ike.eap.message.EapMessage.EAP_CODE_REQUEST;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_IDENTITY_RESPONSE;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.ID_INT;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.IMSI;
+import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
+import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import com.android.ike.eap.EapResult.EapResponse;
+import com.android.ike.eap.message.EapData;
+import com.android.ike.eap.message.EapMessage;
+import com.android.ike.eap.message.simaka.EapAkaPrimeTypeData;
+import com.android.ike.eap.message.simaka.EapAkaTypeData;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
+import com.android.ike.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
+import com.android.ike.eap.statemachine.EapAkaPrimeMethodStateMachine.ChallengeState;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class EapAkaPrimeIdentityStateTest extends EapAkaPrimeStateTest {
+ @Before
+ public void setUp() {
+ super.setUp();
+
+ mStateMachine.transitionTo(mStateMachine.new IdentityState());
+ }
+
+ @Test
+ public void testProcessIdentityRequest() throws Exception {
+ EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
+ EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
+
+ DecodeResult<EapAkaTypeData> decodeResult =
+ new DecodeResult<>(
+ new EapAkaPrimeTypeData(EAP_AKA_IDENTITY, Arrays.asList(new AtAnyIdReq())));
+ when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
+ when(mMockTelephonyManager.getSubscriberId()).thenReturn(IMSI);
+
+ EapResponse eapResponse = (EapResponse) mStateMachine.process(eapMessage);
+ assertArrayEquals(EAP_AKA_PRIME_IDENTITY_RESPONSE, eapResponse.packet);
+
+ verify(mMockTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
+ verify(mMockTelephonyManager).getSubscriberId();
+ verifyNoMoreInteractions(mMockTypeDataDecoder, mMockTelephonyManager);
+ }
+
+ @Test
+ public void testProcessTransitionToChallengeState() throws Exception {
+ EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
+ EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
+
+ // Don't actually need any attributes in the attributeMap, since we only care about the
+ // state transition here.
+ DecodeResult<EapAkaTypeData> decodeResult =
+ new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, new ArrayList<>()));
+ when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
+
+ mStateMachine.process(eapMessage);
+
+ assertTrue(mStateMachine.getState() instanceof ChallengeState);
+
+ // decoded in IdentityState and ChallengeState
+ verify(mMockTypeDataDecoder, times(2)).decode(DUMMY_EAP_TYPE_DATA);
+ verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java
new file mode 100644
index 00000000..c96f3fe2
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.statemachine;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.ike.eap.statemachine.EapAkaMethodStateMachine.CreatedState;
+
+import org.junit.Test;
+
+public class EapAkaPrimeMethodStateMachineTest extends EapAkaPrimeTest {
+ @Test
+ public void testEapAkaPrimeMethodStateMachineStartState() {
+ assertTrue(mStateMachine.getState() instanceof CreatedState);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeStateTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeStateTest.java
new file mode 100644
index 00000000..98d7bc38
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeStateTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.statemachine;
+
+import static com.android.ike.eap.message.EapData.EAP_NOTIFICATION;
+import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME;
+import static com.android.ike.eap.message.EapMessage.EAP_CODE_FAILURE;
+import static com.android.ike.eap.message.EapMessage.EAP_CODE_REQUEST;
+import static com.android.ike.eap.message.EapMessage.EAP_CODE_SUCCESS;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_CLIENT_ERROR_UNABLE_TO_PROCESS;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.ID_INT;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import com.android.ike.eap.EapResult;
+import com.android.ike.eap.EapResult.EapError;
+import com.android.ike.eap.EapResult.EapFailure;
+import com.android.ike.eap.EapResult.EapResponse;
+import com.android.ike.eap.exceptions.EapInvalidRequestException;
+import com.android.ike.eap.message.EapData;
+import com.android.ike.eap.message.EapMessage;
+import com.android.ike.eap.message.simaka.EapAkaTypeData;
+import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
+import com.android.ike.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
+import com.android.ike.eap.statemachine.EapMethodStateMachine.EapMethodState;
+import com.android.ike.eap.statemachine.EapMethodStateMachine.FinalState;
+
+import org.junit.Test;
+
+public class EapAkaPrimeStateTest extends EapAkaPrimeTest {
+ protected static final String NOTIFICATION_MESSAGE = "test";
+
+ @Test
+ public void testProcessNotification() throws Exception {
+ EapData eapData = new EapData(EAP_NOTIFICATION, NOTIFICATION_MESSAGE.getBytes());
+ EapMessage notification = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
+ EapMethodState preNotification = (EapMethodState) mStateMachine.getState();
+
+ EapResult result = mStateMachine.process(notification);
+ assertEquals(preNotification, mStateMachine.getState());
+ verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
+
+ EapResponse eapResponse = (EapResponse) result;
+ assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
+ }
+
+ @Test
+ public void testProcessInvalidDecodeResult() throws Exception {
+ EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
+ EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
+ EapMethodState preProcess = (EapMethodState) mStateMachine.getState();
+
+ AtClientErrorCode atClientErrorCode = AtClientErrorCode.UNABLE_TO_PROCESS;
+ DecodeResult<EapAkaTypeData> decodeResult = new DecodeResult<>(atClientErrorCode);
+ when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
+
+ EapResult result = mStateMachine.process(eapMessage);
+ assertEquals(preProcess, mStateMachine.getState());
+ verify(mMockTypeDataDecoder).decode(DUMMY_EAP_TYPE_DATA);
+ verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
+
+ EapResponse eapResponse = (EapResponse) result;
+ assertArrayEquals(EAP_AKA_PRIME_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
+ }
+
+ @Test
+ public void testHandleEapFailure() throws Exception {
+ EapResult result = mStateMachine.process(new EapMessage(EAP_CODE_FAILURE, ID_INT, null));
+ assertTrue(result instanceof EapFailure);
+ assertTrue(mStateMachine.getState() instanceof FinalState);
+ }
+
+ @Test
+ public void testHandleEapSuccess() throws Exception {
+ EapResult result = mStateMachine.process(new EapMessage(EAP_CODE_SUCCESS, ID_INT, null));
+ EapError eapError = (EapError) result;
+ assertTrue(eapError.cause instanceof EapInvalidRequestException);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeTest.java
new file mode 100644
index 00000000..4a8e3941
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ike.eap.statemachine;
+
+import static android.telephony.TelephonyManager.APPTYPE_USIM;
+
+import static com.android.ike.TestUtils.hexStringToByteArray;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+
+import com.android.ike.eap.EapSessionConfig.EapAkaPrimeConfig;
+import com.android.ike.eap.message.simaka.EapAkaPrimeTypeData;
+
+import org.junit.Before;
+
+public class EapAkaPrimeTest {
+
+ // newtork name example in RFC 5448#3.1
+ protected static final int SUB_ID = 1;
+ protected static final String PEER_NETWORK_NAME = "foo:bar";
+ protected static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = false;
+ protected static final EapAkaPrimeConfig EAP_AKA_PRIME_CONFIG =
+ new EapAkaPrimeConfig(
+ SUB_ID, APPTYPE_USIM, PEER_NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES);
+ protected static final byte[] DUMMY_EAP_TYPE_DATA = hexStringToByteArray("112233445566");
+
+ // EAP-Identity = hex("test@android.net")
+ protected static final byte[] EAP_IDENTITY_BYTES =
+ hexStringToByteArray("7465737440616E64726F69642E6E6574");
+
+ protected Context mMockContext;
+ protected TelephonyManager mMockTelephonyManager;
+ protected EapAkaPrimeTypeData.EapAkaPrimeTypeDataDecoder mMockTypeDataDecoder;
+
+ protected EapAkaPrimeMethodStateMachine mStateMachine;
+
+ @Before
+ public void setUp() {
+ mMockContext = mock(Context.class);
+ mMockTelephonyManager = mock(TelephonyManager.class);
+ mMockTypeDataDecoder = mock(EapAkaPrimeTypeData.EapAkaPrimeTypeDataDecoder.class);
+
+ when(mMockContext.getSystemService(eq(Context.TELEPHONY_SERVICE)))
+ .thenReturn(mMockTelephonyManager);
+ when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
+ .thenReturn(mMockTelephonyManager);
+
+ mStateMachine =
+ new EapAkaPrimeMethodStateMachine(
+ mMockContext,
+ EAP_IDENTITY_BYTES,
+ EAP_AKA_PRIME_CONFIG,
+ mMockTypeDataDecoder);
+
+ verify(mMockContext).getSystemService(eq(Context.TELEPHONY_SERVICE));
+ verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/MethodStateTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/MethodStateTest.java
index 93ee03d0..c719e7f7 100644
--- a/tests/iketests/src/java/com/android/ike/eap/statemachine/MethodStateTest.java
+++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/MethodStateTest.java
@@ -21,6 +21,7 @@ import static android.telephony.TelephonyManager.APPTYPE_USIM;
import static com.android.ike.eap.message.EapMessage.EAP_CODE_FAILURE;
import static com.android.ike.eap.message.EapMessage.EAP_CODE_SUCCESS;
import static com.android.ike.eap.message.EapMessage.EAP_HEADER_LENGTH;
+import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_REQUEST;
import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_FAILURE_PACKET;
import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_REQUEST_AKA;
import static com.android.ike.eap.message.EapTestMessageDefinitions.EAP_REQUEST_IDENTITY_PACKET;
@@ -63,6 +64,8 @@ import java.security.SecureRandom;
public class MethodStateTest extends EapStateTest {
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
+ private static final String NETWORK_NAME = "android.net";
+ private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true;
@Before
@Override
@@ -105,6 +108,23 @@ public class MethodStateTest extends EapStateTest {
}
@Test
+ public void testProcessTransitionToEapAkaPrime() {
+ // make EapStateMachine with EAP-AKA' configurations
+ EapSessionConfig eapSessionConfig =
+ new EapSessionConfig.Builder()
+ .setEapAkaPrimeConfig(
+ 0, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES)
+ .build();
+ mEapStateMachine = new EapStateMachine(mContext, eapSessionConfig, new SecureRandom());
+
+ mEapStateMachine.process(EAP_AKA_PRIME_REQUEST);
+
+ assertTrue(mEapStateMachine.getState() instanceof MethodState);
+ MethodState methodState = (MethodState) mEapStateMachine.getState();
+ assertTrue(methodState.mEapMethodStateMachine instanceof EapAkaPrimeMethodStateMachine);
+ }
+
+ @Test
public void testProcessTransitionToEapMsChapV2() {
// make EapStateMachine with EAP MSCHAPv2 configurations
EapSessionConfig eapSessionConfig =
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java
index 392084f7..7abcc581 100644
--- a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java
@@ -97,7 +97,9 @@ public final class IkeSessionOptionsTest {
@Test
public void testBuildWithPsk() throws Exception {
IkeSessionOptions sessionOptions =
- new IkeSessionOptions.Builder(REMOTE_IPV4_ADDRESS, mUdpEncapSocket)
+ new IkeSessionOptions.Builder()
+ .setServerAddress(REMOTE_IPV4_ADDRESS)
+ .setUdpEncapsulationSocket(mUdpEncapSocket)
.addSaProposal(mIkeSaProposal)
.setLocalIdentification(mLocalIdentification)
.setRemoteIdentification(mRemoteIdentification)
@@ -123,7 +125,9 @@ public final class IkeSessionOptionsTest {
EapSessionConfig eapConfig = mock(EapSessionConfig.class);
IkeSessionOptions sessionOptions =
- new IkeSessionOptions.Builder(REMOTE_IPV4_ADDRESS, mUdpEncapSocket)
+ new IkeSessionOptions.Builder()
+ .setServerAddress(REMOTE_IPV4_ADDRESS)
+ .setUdpEncapsulationSocket(mUdpEncapSocket)
.addSaProposal(mIkeSaProposal)
.setLocalIdentification(mLocalIdentification)
.setRemoteIdentification(mRemoteIdentification)
@@ -148,7 +152,10 @@ public final class IkeSessionOptionsTest {
@Test
public void testBuildWithoutSaProposal() throws Exception {
try {
- new IkeSessionOptions.Builder(REMOTE_IPV4_ADDRESS, mUdpEncapSocket).build();
+ new IkeSessionOptions.Builder()
+ .setServerAddress(REMOTE_IPV4_ADDRESS)
+ .setUdpEncapsulationSocket(mUdpEncapSocket)
+ .build();
fail("Expected to fail due to absence of SA proposal.");
} catch (IllegalArgumentException expected) {
}
@@ -157,7 +164,9 @@ public final class IkeSessionOptionsTest {
@Test
public void testBuildWithoutLocalId() throws Exception {
try {
- new IkeSessionOptions.Builder(REMOTE_IPV4_ADDRESS, mUdpEncapSocket)
+ new IkeSessionOptions.Builder()
+ .setServerAddress(REMOTE_IPV4_ADDRESS)
+ .setUdpEncapsulationSocket(mUdpEncapSocket)
.addSaProposal(mIkeSaProposal)
.setRemoteIdentification(mRemoteIdentification)
.setAuthPsk(PSK)
@@ -170,7 +179,9 @@ public final class IkeSessionOptionsTest {
@Test
public void testBuildWithoutSetAuth() throws Exception {
try {
- new IkeSessionOptions.Builder(REMOTE_IPV4_ADDRESS, mUdpEncapSocket)
+ new IkeSessionOptions.Builder()
+ .setServerAddress(REMOTE_IPV4_ADDRESS)
+ .setUdpEncapsulationSocket(mUdpEncapSocket)
.addSaProposal(mIkeSaProposal)
.setLocalIdentification(mLocalIdentification)
.setRemoteIdentification(mRemoteIdentification)
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java
index 6d93255d..819c3280 100644
--- a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java
@@ -724,7 +724,9 @@ public final class IkeSessionStateMachineTest {
}
private IkeSessionOptions.Builder buildIkeSessionOptionsCommon() throws Exception {
- return new IkeSessionOptions.Builder(REMOTE_ADDRESS, mUdpEncapSocket)
+ return new IkeSessionOptions.Builder()
+ .setServerAddress(REMOTE_ADDRESS)
+ .setUdpEncapsulationSocket(mUdpEncapSocket)
.addSaProposal(buildSaProposal())
.setLocalIdentification(new IkeIpv4AddrIdentification((Inet4Address) LOCAL_ADDRESS))
.setRemoteIdentification(
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionTest.java
index e33a67cc..28a13110 100644
--- a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionTest.java
@@ -73,8 +73,9 @@ public final class IkeSessionTest {
}
private IkeSessionOptions buildIkeSessionOptions() throws Exception {
- return new IkeSessionOptions.Builder(
- REMOTE_ADDRESS, mIpSecManager.openUdpEncapsulationSocket())
+ return new IkeSessionOptions.Builder()
+ .setServerAddress(REMOTE_ADDRESS)
+ .setUdpEncapsulationSocket(mIpSecManager.openUdpEncapsulationSocket())
.addSaProposal(IkeSessionStateMachineTest.buildSaProposal())
.setLocalIdentification(new IkeIpv4AddrIdentification((Inet4Address) LOCAL_ADDRESS))
.setRemoteIdentification(