diff options
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( |