diff options
Diffstat (limited to 'src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java')
-rw-r--r-- | src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java | 1162 |
1 files changed, 0 insertions, 1162 deletions
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java b/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java deleted file mode 100644 index 73d6752d..00000000 --- a/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java +++ /dev/null @@ -1,1162 +0,0 @@ -/* - * 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.internal.net.eap.message.simaka; - -import static com.android.internal.net.eap.EapAuthenticator.LOG; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAtPaddingException; -import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException; -import com.android.internal.net.eap.exceptions.simaka.EapSimInvalidAtRandException; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * EapSimAkaAttribute represents a single EAP SIM/AKA Attribute. - * - * @see <a href="https://tools.ietf.org/html/rfc4186">RFC 4186, Extensible Authentication - * Protocol for Subscriber Identity Modules (EAP-SIM)</a> - * @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://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml">EAP SIM/AKA - * Attributes</a> - */ -public abstract class EapSimAkaAttribute { - static final int LENGTH_SCALING = 4; - - private static final int MIN_ATTR_LENGTH = 4; - - public static final int SKIPPABLE_ATTRIBUTE_RANGE_START = 128; - - // EAP non-Skippable Attribute values defined by IANA - // https://www.iana.org/assignments/eapsimaka-numbers/eapsimaka-numbers.xhtml - public static final int EAP_AT_RAND = 1; - public static final int EAP_AT_AUTN = 2; - public static final int EAP_AT_RES = 3; - public static final int EAP_AT_AUTS = 4; - public static final int EAP_AT_PADDING = 6; - public static final int EAP_AT_NONCE_MT = 7; - public static final int EAP_AT_PERMANENT_ID_REQ = 10; - public static final int EAP_AT_MAC = 11; - public static final int EAP_AT_NOTIFICATION = 12; - public static final int EAP_AT_ANY_ID_REQ = 13; - public static final int EAP_AT_IDENTITY = 14; - public static final int EAP_AT_VERSION_LIST = 15; - public static final int EAP_AT_SELECTED_VERSION = 16; - public static final int EAP_AT_FULLAUTH_ID_REQ = 17; - public static final int EAP_AT_COUNTER = 19; - 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 - public static final int EAP_AT_IV = 129; - public static final int EAP_AT_ENCR_DATA = 130; - public static final int EAP_AT_NEXT_PSEUDONYM = 132; - 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 { - EAP_ATTRIBUTE_STRING.put(EAP_AT_RAND, "AT_RAND"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_AUTN, "AT_AUTN"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_RES, "AT_RES"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_AUTS, "AT_AUTS"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_PADDING, "AT_PADDING"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_NONCE_MT, "AT_NONCE_MT"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_PERMANENT_ID_REQ, "AT_PERMANENT_ID_REQ"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_MAC, "AT_MAC"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_NOTIFICATION, "AT_NOTIFICATION"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_ANY_ID_REQ, "AT_ANY_ID_REQ"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_IDENTITY, "AT_IDENTITY"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_VERSION_LIST, "AT_VERSION_LIST"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_SELECTED_VERSION, "AT_SELECTED_VERSION"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_FULLAUTH_ID_REQ, "AT_FULLAUTH_ID_REQ"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_COUNTER, "AT_COUNTER"); - 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"); - EAP_ATTRIBUTE_STRING.put(EAP_AT_NEXT_PSEUDONYM, "AT_NEXT_PSEUDONYM"); - 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; - public final int lengthInBytes; - - protected EapSimAkaAttribute(int attributeType, int lengthInBytes) - throws EapSimAkaInvalidAttributeException { - this.attributeType = attributeType; - this.lengthInBytes = lengthInBytes; - - if (lengthInBytes % LENGTH_SCALING != 0) { - throw new EapSimAkaInvalidAttributeException("Attribute length must be multiple of 4"); - } - } - - /** - * Encodes this EapSimAkaAttribute into the given ByteBuffer - * - * @param byteBuffer the ByteBuffer that this instance will be written to - */ - public abstract void encode(ByteBuffer byteBuffer); - - protected void encodeAttributeHeader(ByteBuffer byteBuffer) { - byteBuffer.put((byte) attributeType); - byteBuffer.put((byte) (lengthInBytes / LENGTH_SCALING)); - } - - void consumePadding(int bytesUsed, ByteBuffer byteBuffer) { - int paddingRemaining = lengthInBytes - bytesUsed; - byteBuffer.get(new byte[paddingRemaining]); - } - - void addPadding(int bytesUsed, ByteBuffer byteBuffer) { - int paddingNeeded = lengthInBytes - bytesUsed; - byteBuffer.put(new byte[paddingNeeded]); - } - - /** - * EapSimAkaUnsupportedAttribute represents any unsupported, skippable EAP-SIM attribute. - */ - public static class EapSimAkaUnsupportedAttribute extends EapSimAkaAttribute { - // Attribute Type (1B) + Attribute Length (1B) = 2B Header - private static final int HEADER_BYTES = 2; - - public final byte[] data; - - public EapSimAkaUnsupportedAttribute( - int attributeType, - int lengthInBytes, - ByteBuffer byteBuffer) throws EapSimAkaInvalidAttributeException { - super(attributeType, lengthInBytes); - - // Attribute not supported, but remaining attribute still needs to be saved - int remainingBytes = lengthInBytes - HEADER_BYTES; - data = new byte[remainingBytes]; - byteBuffer.get(data); - } - - @VisibleForTesting - public EapSimAkaUnsupportedAttribute(int attributeType, int lengthInBytes, byte[] data) - throws EapSimAkaInvalidAttributeException { - super(attributeType, lengthInBytes); - this.data = data; - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.put(data); - } - } - - /** - * AtVersionList represents the AT_VERSION_LIST attribute defined in RFC 4186#10.2 - */ - public static class AtVersionList extends EapSimAkaAttribute { - private static final int BYTES_PER_VERSION = 2; - - public final List<Integer> versions = new ArrayList<>(); - - public AtVersionList(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_VERSION_LIST, lengthInBytes); - - // number of bytes used to represent list (RFC 4186 Section 10.2) - int bytesInList = Short.toUnsignedInt(byteBuffer.getShort()); - if (bytesInList % BYTES_PER_VERSION != 0) { - throw new EapSimAkaInvalidAttributeException( - "Actual Version List Length must be multiple of 2"); - } - - int numVersions = bytesInList / BYTES_PER_VERSION; - for (int i = 0; i < numVersions; i++) { - versions.add(Short.toUnsignedInt(byteBuffer.getShort())); - } - - int bytesUsed = MIN_ATTR_LENGTH + (BYTES_PER_VERSION * versions.size()); - consumePadding(bytesUsed, byteBuffer); - } - - @VisibleForTesting - public AtVersionList(int lengthInBytes, int... versions) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_VERSION_LIST, lengthInBytes); - for (int version : versions) { - this.versions.add(version); - } - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - - byteBuffer.putShort((short) (versions.size() * BYTES_PER_VERSION)); - for (int i : versions) { - byteBuffer.putShort((short) i); - } - - int bytesUsed = MIN_ATTR_LENGTH + (BYTES_PER_VERSION * versions.size()); - addPadding(bytesUsed, byteBuffer); - } - } - - /** - * AtSelectedVersion represents the AT_SELECTED_VERSION attribute defined in RFC 4186#10.3 - */ - public static class AtSelectedVersion extends EapSimAkaAttribute { - private static final String TAG = AtSelectedVersion.class.getSimpleName(); - private static final int LENGTH = LENGTH_SCALING; - - public static final int SUPPORTED_VERSION = 1; - - public final int selectedVersion; - - public AtSelectedVersion(int lengthInBytes, int selectedVersion) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_SELECTED_VERSION, LENGTH); - this.selectedVersion = selectedVersion; - - if (lengthInBytes != LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - } - - @VisibleForTesting - public AtSelectedVersion(int selectedVersion) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_SELECTED_VERSION, LENGTH); - this.selectedVersion = selectedVersion; - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.putShort((short) selectedVersion); - } - - /** - * Constructs and returns an AtSelectedVersion for the only supported version of EAP-SIM - * - * @return an AtSelectedVersion for the supported version (1) of EAP-SIM - */ - public static AtSelectedVersion getSelectedVersion() { - try { - return new AtSelectedVersion(LENGTH, SUPPORTED_VERSION); - } catch (EapSimAkaInvalidAttributeException ex) { - // this should never happen - LOG.wtf(TAG, - "Error thrown while creating AtSelectedVersion with correct length", ex); - throw new AssertionError("Impossible exception encountered", ex); - } - } - } - - /** - * AtNonceMt represents the AT_NONCE_MT attribute defined in RFC 4186#10.4 - */ - public static class AtNonceMt extends EapSimAkaAttribute { - private static final int LENGTH = 5 * LENGTH_SCALING; - private static final int RESERVED_BYTES = 2; - - public static final int NONCE_MT_LENGTH = 16; - - public final byte[] nonceMt = new byte[NONCE_MT_LENGTH]; - - public AtNonceMt(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_NONCE_MT, LENGTH); - if (lengthInBytes != LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - - // next two bytes are reserved (RFC 4186 Section 10.4) - byteBuffer.get(new byte[RESERVED_BYTES]); - byteBuffer.get(nonceMt); - } - - @VisibleForTesting - public AtNonceMt(byte[] nonceMt) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_NONCE_MT, LENGTH); - - if (nonceMt.length != NONCE_MT_LENGTH) { - throw new EapSimAkaInvalidAttributeException("NonceMt length must be 16B"); - } - System.arraycopy(nonceMt, 0, this.nonceMt, 0, NONCE_MT_LENGTH); - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.put(new byte[RESERVED_BYTES]); - byteBuffer.put(nonceMt); - } - } - - private abstract static class AtIdReq extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = LENGTH_SCALING; - private static final int RESERVED_BYTES = 2; - - protected AtIdReq(int lengthInBytes, int attributeType, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(attributeType, ATTR_LENGTH); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - - // next two bytes are reserved (RFC 4186 Section 10.5-10.7) - byteBuffer.get(new byte[RESERVED_BYTES]); - } - - @VisibleForTesting - protected AtIdReq(int attributeType) throws EapSimAkaInvalidAttributeException { - super(attributeType, ATTR_LENGTH); - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.put(new byte[RESERVED_BYTES]); - } - } - - /** - * AtPermanentIdReq represents the AT_PERMANENT_ID_REQ attribute defined in RFC 4186#10.5 and - * RFC 4187#10.2 - */ - public static class AtPermanentIdReq extends AtIdReq { - public AtPermanentIdReq(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(lengthInBytes, EAP_AT_PERMANENT_ID_REQ, byteBuffer); - } - - @VisibleForTesting - public AtPermanentIdReq() throws EapSimAkaInvalidAttributeException { - super(EAP_AT_PERMANENT_ID_REQ); - } - } - - /** - * AtAnyIdReq represents the AT_ANY_ID_REQ attribute defined in RFC 4186#10.6 and RFC 4187#10.3 - */ - public static class AtAnyIdReq extends AtIdReq { - public AtAnyIdReq(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(lengthInBytes, EAP_AT_ANY_ID_REQ, byteBuffer); - } - - @VisibleForTesting - public AtAnyIdReq() throws EapSimAkaInvalidAttributeException { - super(EAP_AT_ANY_ID_REQ); - } - } - - /** - * AtFullauthIdReq represents the AT_FULLAUTH_ID_REQ attribute defined in RFC 4186#10.7 and RFC - * 4187#10.4 - */ - public static class AtFullauthIdReq extends AtIdReq { - public AtFullauthIdReq(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(lengthInBytes, EAP_AT_FULLAUTH_ID_REQ, byteBuffer); - } - - @VisibleForTesting - public AtFullauthIdReq() throws EapSimAkaInvalidAttributeException { - super(EAP_AT_FULLAUTH_ID_REQ); - } - } - - /** - * AtIdentity represents the AT_IDENTITY attribute defined in RFC 4186#10.8 and RFC 4187#10.5 - */ - public static class AtIdentity extends EapSimAkaAttribute { - public final byte[] identity; - - public AtIdentity(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_IDENTITY, lengthInBytes); - - int identityLength = Short.toUnsignedInt(byteBuffer.getShort()); - identity = new byte[identityLength]; - byteBuffer.get(identity); - - int bytesUsed = MIN_ATTR_LENGTH + identityLength; - consumePadding(bytesUsed, byteBuffer); - } - - @VisibleForTesting - public AtIdentity(int lengthInBytes, byte[] identity) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_IDENTITY, lengthInBytes); - this.identity = identity; - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.putShort((short) identity.length); - byteBuffer.put(identity); - - int bytesUsed = MIN_ATTR_LENGTH + identity.length; - addPadding(bytesUsed, byteBuffer); - } - - /** - * Creates and returns an AtIdentity instance for the given identity. - * - * @param identity byte-array representing the identity for the AtIdentity - * @return AtIdentity instance for the given identity byte-array - */ - public static AtIdentity getAtIdentity(byte[] identity) - throws EapSimAkaInvalidAttributeException { - int lengthInBytes = MIN_ATTR_LENGTH + identity.length; - if (lengthInBytes % LENGTH_SCALING != 0) { - lengthInBytes += LENGTH_SCALING - (lengthInBytes % LENGTH_SCALING); - } - - return new AtIdentity(lengthInBytes, identity); - } - } - - /** - * AtRandSim represents the AT_RAND attribute for EAP-SIM defined in RFC 4186#10.9 - */ - public static class AtRandSim extends EapSimAkaAttribute { - private static final int RAND_LENGTH = 16; - private static final int RESERVED_BYTES = 2; - private static final int MIN_RANDS = 2; - private static final int MAX_RANDS = 3; - - public final List<byte[]> rands = new ArrayList<>(MAX_RANDS); - - public AtRandSim(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_RAND, lengthInBytes); - - // next two bytes are reserved (RFC 4186 Section 10.9) - byteBuffer.get(new byte[RESERVED_BYTES]); - - int numRands = (lengthInBytes - MIN_ATTR_LENGTH) / RAND_LENGTH; - if (!isValidNumRands(numRands)) { - throw new EapSimInvalidAtRandException("Unexpected number of rands: " + numRands); - } - - for (int i = 0; i < numRands; i++) { - byte[] rand = new byte[RAND_LENGTH]; - byteBuffer.get(rand); - - // check for rand being unique (RFC 4186 Section 10.9) - for (int j = 0; j < i; j++) { - byte[] otherRand = rands.get(j); - if (Arrays.equals(rand, otherRand)) { - throw new EapSimAkaInvalidAttributeException("Received identical RANDs"); - } - } - rands.add(rand); - } - } - - @VisibleForTesting - public AtRandSim(int lengthInBytes, byte[]... rands) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_RAND, lengthInBytes); - - if (!isValidNumRands(rands.length)) { - throw new EapSimInvalidAtRandException("Unexpected number of rands: " - + rands.length); - } - for (byte[] rand : rands) { - this.rands.add(rand); - } - } - - private boolean isValidNumRands(int numRands) { - // numRands is valid iff 2 <= numRands <= 3 - return MIN_RANDS <= numRands && numRands <= MAX_RANDS; - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.put(new byte[RESERVED_BYTES]); - - for (byte[] rand : rands) { - byteBuffer.put(rand); - } - } - } - - /** - * AtRandAka represents the AT_RAND attribute for EAP-AKA defined in RFC 4187#10.6 - */ - public static class AtRandAka extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = 5 * LENGTH_SCALING; - private static final int RAND_LENGTH = 16; - private static final int RESERVED_BYTES = 2; - - public final byte[] rand = new byte[RAND_LENGTH]; - - public AtRandAka(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_RAND, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Length must be 20B"); - } - - // next two bytes are reserved (RFC 4187#10.6) - byteBuffer.get(new byte[RESERVED_BYTES]); - - byteBuffer.get(rand); - } - - @VisibleForTesting - public AtRandAka(byte[] rand) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_RAND, ATTR_LENGTH); - - if (rand.length != RAND_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Rand must be 16B"); - } - - System.arraycopy(rand, 0, this.rand, 0, RAND_LENGTH); - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.put(new byte[RESERVED_BYTES]); - byteBuffer.put(rand); - } - } - - /** - * AtPadding represents the AT_PADDING attribute defined in RFC 4186#10.12 and RFC 4187#10.12 - */ - public static class AtPadding extends EapSimAkaAttribute { - private static final int ATTR_HEADER = 2; - - public AtPadding(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_PADDING, lengthInBytes); - - int remainingBytes = lengthInBytes - ATTR_HEADER; - for (int i = 0; i < remainingBytes; i++) { - // Padding must be checked to all be 0x00 bytes (RFC 4186 Section 10.12) - if (byteBuffer.get() != 0) { - throw new EapSimAkaInvalidAtPaddingException("Padding bytes must all be 0x00"); - } - } - } - - @VisibleForTesting - public AtPadding(int lengthInBytes) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_PADDING, lengthInBytes); - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - - addPadding(ATTR_HEADER, byteBuffer); - } - } - - /** - * AtMac represents the AT_MAC attribute defined in RFC 4186#10.14 and RFC 4187#10.15 - */ - public static class AtMac extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = 5 * LENGTH_SCALING; - private static final int RESERVED_BYTES = 2; - - public static final int MAC_LENGTH = 4 * LENGTH_SCALING; - - public final byte[] mac; - - public AtMac(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_MAC, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - - // next two bytes are reserved (RFC 4186 Section 10.14) - byteBuffer.get(new byte[RESERVED_BYTES]); - - mac = new byte[MAC_LENGTH]; - byteBuffer.get(mac); - } - - // Used for calculating MACs. Per RFC 4186 Section 10.14, the MAC should be calculated over - // the entire packet, with the value field of the MAC attribute set to zero. - public AtMac() throws EapSimAkaInvalidAttributeException { - super(EAP_AT_MAC, ATTR_LENGTH); - mac = new byte[MAC_LENGTH]; - } - - public AtMac(byte[] mac) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_MAC, ATTR_LENGTH); - this.mac = mac; - - if (mac.length != MAC_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid length for MAC"); - } - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.put(new byte[RESERVED_BYTES]); - byteBuffer.put(mac); - } - } - - /** - * AtCounter represents the AT_COUNTER attribute defined in RFC 4186#10.15 and RFC 4187#10.16 - */ - public static class AtCounter extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = LENGTH_SCALING; - - public final int counter; - - public AtCounter(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_COUNTER, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - - this.counter = Short.toUnsignedInt(byteBuffer.getShort()); - } - - @VisibleForTesting - public AtCounter(int counter) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_COUNTER, ATTR_LENGTH); - this.counter = counter; - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.putShort((short) counter); - } - } - - - /** - * AtCounterTooSmall represents the AT_COUNTER_TOO_SMALL attribute defined in RFC 4186#10.16 and - * RFC 4187#10.17 - */ - public static class AtCounterTooSmall extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = LENGTH_SCALING; - private static final int ATTR_HEADER = 2; - - public AtCounterTooSmall(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_COUNTER_TOO_SMALL, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - consumePadding(ATTR_HEADER, byteBuffer); - } - - public AtCounterTooSmall() throws EapSimAkaInvalidAttributeException { - super(EAP_AT_COUNTER_TOO_SMALL, ATTR_LENGTH); - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - addPadding(ATTR_HEADER, byteBuffer); - } - } - - /** - * AtNonceS represents the AT_NONCE_S attribute defined in RFC 4186#10.17 and RFC 4187#10.18 - * - * <p>This Nonce is generated by the server and used for fast re-authentication only. - */ - public static class AtNonceS extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = 5 * LENGTH_SCALING; - private static final int NONCE_S_LENGTH = 4 * LENGTH_SCALING; - private static final int RESERVED_BYTES = 2; - - public final byte[] nonceS = new byte[NONCE_S_LENGTH]; - - public AtNonceS(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_NONCE_S, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - - // next two bytes are reserved (RFC 4186 Section 10.17) - byteBuffer.get(new byte[RESERVED_BYTES]); - byteBuffer.get(nonceS); - } - - @VisibleForTesting - public AtNonceS(byte[] nonceS) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_NONCE_S, ATTR_LENGTH); - - if (nonceS.length != NONCE_S_LENGTH) { - throw new EapSimAkaInvalidAttributeException("NonceS length must be 16B"); - } - - System.arraycopy(nonceS, 0, this.nonceS, 0, NONCE_S_LENGTH); - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.put(new byte[RESERVED_BYTES]); - byteBuffer.put(nonceS); - } - } - - /** - * AtNotification represents the AT_NOTIFICATION attribute defined in RFC 4186#10.18 and RFC - * 4187#10.19 - */ - public static class AtNotification extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = 4; - private static final int SUCCESS_MASK = 0x8000; - private static final int PRE_SUCCESSFUL_CHALLENGE_MASK = 0x4000; - - // Notification codes defined in RFC 4186 Section 10.18 - public static final int GENERAL_FAILURE_POST_CHALLENGE = 0; - public static final int GENERAL_FAILURE_PRE_CHALLENGE = 16384; // 0x4000 - public static final int SUCCESS = 32768; // 0x8000 - public static final int DENIED_ACCESS_POST_CHALLENGE = 1026; - public static final int USER_NOT_SUBSCRIBED_POST_CHALLENGE = 1031; - - private static final Map<Integer, String> CODE_DEFS = loadCodeDefs(); - - public final boolean isSuccessCode; - public final boolean isPreSuccessfulChallenge; - public final int notificationCode; - - public AtNotification(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_NOTIFICATION, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - - notificationCode = Short.toUnsignedInt(byteBuffer.getShort()); - - // If Success bit == 0, failure is implied - isSuccessCode = (notificationCode & SUCCESS_MASK) != 0; - - // if Phase bit == 0, notification code can only be used after a successful - isPreSuccessfulChallenge = (notificationCode & PRE_SUCCESSFUL_CHALLENGE_MASK) != 0; - - if (isSuccessCode && isPreSuccessfulChallenge) { - throw new EapSimAkaInvalidAttributeException("Invalid state specified"); - } - } - - @VisibleForTesting - public AtNotification(int notificationCode) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_NOTIFICATION, ATTR_LENGTH); - this.notificationCode = notificationCode; - - // If Success bit == 0, failure is implied - isSuccessCode = (notificationCode & SUCCESS_MASK) != 0; - - // if Phase bit == 0, notification code can only be used after a successful challenge - isPreSuccessfulChallenge = (notificationCode & PRE_SUCCESSFUL_CHALLENGE_MASK) != 0; - - if (isSuccessCode && isPreSuccessfulChallenge) { - throw new EapSimAkaInvalidAttributeException("Invalid state specified"); - } - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.putShort((short) notificationCode); - } - - @Override - public String toString() { - String description = CODE_DEFS.getOrDefault(notificationCode, "Code not recognized"); - return "{Notification Code=" + notificationCode + ", descr=" + description + "}"; - } - - private static Map<Integer, String> loadCodeDefs() { - Map<Integer, String> defs = new HashMap<>(); - defs.put(GENERAL_FAILURE_POST_CHALLENGE, - "General failure after authentication. (Implies failure, used after successful" - + " authentication.)"); - defs.put(GENERAL_FAILURE_PRE_CHALLENGE, - "General failure. (Implies failure, used before authentication.)"); - defs.put(SUCCESS, - "Success. User has been successfully authenticated. (Does not imply failure," - + " used after successful authentication)."); - defs.put(DENIED_ACCESS_POST_CHALLENGE, - "User has been temporarily denied access to the requested service. (Implies" - + " failure, used after successful authentication.)"); - defs.put(USER_NOT_SUBSCRIBED_POST_CHALLENGE, - "User has not subscribed to the requested service. (Implies failure, used" - + " after successful authentication.)"); - return defs; - } - } - - /** - * AtClientErrorCode represents the AT_CLIENT_ERROR_CODE attribute defined in RFC 4186#10.19 and - * RFC 4187#10.20 - */ - public static class AtClientErrorCode extends EapSimAkaAttribute { - private static final String TAG = AtClientErrorCode.class.getSimpleName(); - private static final int ATTR_LENGTH = 4; - - // Error codes defined in RFC 4186 Section 10.19 - public static final AtClientErrorCode UNABLE_TO_PROCESS = getClientErrorCode(0); - public static final AtClientErrorCode UNSUPPORTED_VERSION = getClientErrorCode(1); - public static final AtClientErrorCode INSUFFICIENT_CHALLENGES = getClientErrorCode(2); - public static final AtClientErrorCode STALE_RANDS = getClientErrorCode(3); - - public final int errorCode; - - public AtClientErrorCode(int lengthInBytes, int errorCode) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_CLIENT_ERROR_CODE, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Invalid Length specified"); - } - - this.errorCode = errorCode; - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.putShort((short) errorCode); - } - - private static AtClientErrorCode getClientErrorCode(int errorCode) { - try { - return new AtClientErrorCode(ATTR_LENGTH, errorCode); - } catch (EapSimAkaInvalidAttributeException exception) { - LOG.wtf(TAG, "Exception thrown while making AtClientErrorCodeConstants"); - return null; - } - } - } - - /** - * AtAutn represents the AT_AUTN attribute defined in RFC 4187#10.7 - */ - public static class AtAutn extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = 5 * LENGTH_SCALING; - private static final int AUTN_LENGTH = 16; - private static final int RESERVED_BYTES = 2; - - public final byte[] autn = new byte[AUTN_LENGTH]; - - public AtAutn(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_AUTN, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Length must be 20B"); - } - - // next two bytes are reserved (RFC 4187#10.7) - byteBuffer.get(new byte[RESERVED_BYTES]); - - byteBuffer.get(autn); - } - - @VisibleForTesting - public AtAutn(byte[] autn) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_AUTN, ATTR_LENGTH); - - if (autn.length != AUTN_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Autn must be 16B"); - } - - System.arraycopy(autn, 0, this.autn, 0, AUTN_LENGTH); - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - byteBuffer.put(new byte[RESERVED_BYTES]); - byteBuffer.put(autn); - } - } - - /** - * AtRes respresents the AT_RES attribute defined in RFC 4187#10.8 - */ - public static class AtRes extends EapSimAkaAttribute { - private static final int BITS_PER_BYTE = 8; - private static final int MIN_RES_LEN_BYTES = 4; - private static final int MAX_RES_LEN_BYTES = 16; - - public final byte[] res; - - public AtRes(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_RES, lengthInBytes); - - // RES length is in bits (RFC 4187#10.8). - // RES length should be a multiple of 8 bits (TS 133 105#5.1.7.8) - int resLength = Short.toUnsignedInt(byteBuffer.getShort()); - if (resLength % BITS_PER_BYTE != 0) { - throw new EapSimAkaInvalidAttributeException("RES length must be multiple of 8"); - } - int resLengthBytes = resLength / BITS_PER_BYTE; - if (resLengthBytes < MIN_RES_LEN_BYTES || resLengthBytes > MAX_RES_LEN_BYTES) { - throw new EapSimAkaInvalidAttributeException( - "RES length must be: 4B <= len <= 16B"); - } - - res = new byte[resLengthBytes]; - byteBuffer.get(res); - - int bytesUsed = MIN_ATTR_LENGTH + resLengthBytes; - consumePadding(bytesUsed, byteBuffer); - } - - @VisibleForTesting - public AtRes(int lengthInBytes, byte[] res) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_RES, lengthInBytes); - - if (res.length < MIN_RES_LEN_BYTES || res.length > MAX_RES_LEN_BYTES) { - throw new EapSimAkaInvalidAttributeException( - "RES length must be: 4B <= len <= 16B"); - } - - this.res = res; - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - - int resLenBits = res.length * BITS_PER_BYTE; - byteBuffer.putShort((short) resLenBits); - byteBuffer.put(res); - - int bytesUsed = MIN_ATTR_LENGTH + res.length; - addPadding(bytesUsed, byteBuffer); - } - - /** - * Creates and returns an AtRes instance with the given res value. - * - * @param res byte-array RES value to be used for this - * @return AtRes instance for the given RES value - * @throws EapSimAkaInvalidAttributeException if the given res value has an invalid length - */ - public static AtRes getAtRes(byte[] res) throws EapSimAkaInvalidAttributeException { - // Attributes must be 4B-aligned, so there can be 0 to 3 padding bytes added - int resLenBytes = MIN_ATTR_LENGTH + res.length; - if (resLenBytes % LENGTH_SCALING != 0) { - resLenBytes += LENGTH_SCALING - (resLenBytes % LENGTH_SCALING); - } - - return new AtRes(resLenBytes, res); - } - - /** - * Checks whether the given RES length is valid. - * - * @param resLenBytes the RES length to be checked - * @return true iff the given resLen is valid - */ - public static boolean isValidResLen(int resLenBytes) { - return resLenBytes >= MIN_RES_LEN_BYTES && resLenBytes <= MAX_RES_LEN_BYTES; - } - } - - /** - * AtAuts represents the AT_AUTS attribute defined in RFC 4187#10.9 - */ - public static class AtAuts extends EapSimAkaAttribute { - private static final int ATTR_LENGTH = 4 * LENGTH_SCALING; - public static final int AUTS_LENGTH = 14; - - public final byte[] auts = new byte[AUTS_LENGTH]; - - public AtAuts(int lengthInBytes, ByteBuffer byteBuffer) - throws EapSimAkaInvalidAttributeException { - super(EAP_AT_AUTS, lengthInBytes); - - if (lengthInBytes != ATTR_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Length must be 16B"); - } - - byteBuffer.get(auts); - } - - public AtAuts(byte[] auts) throws EapSimAkaInvalidAttributeException { - super(EAP_AT_AUTS, ATTR_LENGTH); - - if (auts.length != AUTS_LENGTH) { - throw new EapSimAkaInvalidAttributeException("Auts must be 14B"); - } - - System.arraycopy(auts, 0, this.auts, 0, AUTS_LENGTH); - } - - @Override - public void encode(ByteBuffer byteBuffer) { - encodeAttributeHeader(byteBuffer); - - 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); - } - } -} |