1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.net.eap.message; 18 19 import static android.net.eap.EapSessionConfig.EapMethodConfig.EAP_TYPE_AKA; 20 import static android.net.eap.EapSessionConfig.EapMethodConfig.EAP_TYPE_AKA_PRIME; 21 import static android.net.eap.EapSessionConfig.EapMethodConfig.EAP_TYPE_MSCHAP_V2; 22 import static android.net.eap.EapSessionConfig.EapMethodConfig.EAP_TYPE_SIM; 23 import static android.net.eap.EapSessionConfig.EapMethodConfig.EAP_TYPE_TTLS; 24 25 import android.annotation.IntDef; 26 import android.annotation.NonNull; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.nio.ByteBuffer; 31 import java.util.Arrays; 32 import java.util.HashMap; 33 import java.util.HashSet; 34 import java.util.Map; 35 import java.util.Objects; 36 import java.util.Set; 37 38 /** 39 * EapData represents the data-bytes of an EAP-Packet. 40 * 41 * <p>EapData objects will always have a Type-value and the Type-Data bytes that follow. 42 * 43 * EapData objects should be parsed from the Type and Type-Data sections of an EAP Packet, as shown 44 * below: 45 * 46 * +-----------------+-----------------+----------------------------------+ 47 * | Code (1B) | Identifier (1B) | Length (2B) | 48 * +-----------------+-----------------+----------------------------------+ 49 * | Type (1B) | Type-Data ... 50 * +-----------------+----- 51 * 52 * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication 53 * Protocol (EAP)</a> 54 */ 55 public class EapData { 56 @Retention(RetentionPolicy.SOURCE) 57 @IntDef({ 58 EAP_IDENTITY, 59 EAP_NOTIFICATION, 60 EAP_NAK, 61 EAP_TYPE_SIM, 62 EAP_TYPE_AKA, 63 EAP_TYPE_MSCHAP_V2, 64 EAP_TYPE_AKA_PRIME, 65 EAP_TYPE_TTLS 66 }) 67 public @interface EapType {} 68 69 // EAP Type values defined by IANA 70 // https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml 71 public static final int EAP_IDENTITY = 1; 72 public static final int EAP_NOTIFICATION = 2; 73 public static final int EAP_NAK = 3; 74 // EAP_MD5_CHALLENGE unsupported, allowable based on RFC 3748, Section 5.4 75 76 public static final Map<Integer, String> EAP_TYPE_STRING = new HashMap<>(); 77 static { EAP_TYPE_STRING.put(EAP_IDENTITY, "Identity")78 EAP_TYPE_STRING.put(EAP_IDENTITY, "Identity"); EAP_TYPE_STRING.put(EAP_NOTIFICATION, "Notification")79 EAP_TYPE_STRING.put(EAP_NOTIFICATION, "Notification"); EAP_TYPE_STRING.put(EAP_NAK, "Nak")80 EAP_TYPE_STRING.put(EAP_NAK, "Nak"); EAP_TYPE_STRING.put(EAP_TYPE_SIM, "EAP-SIM")81 EAP_TYPE_STRING.put(EAP_TYPE_SIM, "EAP-SIM"); EAP_TYPE_STRING.put(EAP_TYPE_AKA, "EAP-AKA")82 EAP_TYPE_STRING.put(EAP_TYPE_AKA, "EAP-AKA"); EAP_TYPE_STRING.put(EAP_TYPE_MSCHAP_V2, "EAP-MSCHAP-V2")83 EAP_TYPE_STRING.put(EAP_TYPE_MSCHAP_V2, "EAP-MSCHAP-V2"); EAP_TYPE_STRING.put(EAP_TYPE_AKA_PRIME, "EAP-AKA-PRIME")84 EAP_TYPE_STRING.put(EAP_TYPE_AKA_PRIME, "EAP-AKA-PRIME"); EAP_TYPE_STRING.put(EAP_TYPE_TTLS, "EAP-TTLS")85 EAP_TYPE_STRING.put(EAP_TYPE_TTLS, "EAP-TTLS"); 86 } 87 88 private static final Set<Integer> SUPPORTED_TYPES = new HashSet<>(); 89 static { 90 SUPPORTED_TYPES.add(EAP_IDENTITY); 91 SUPPORTED_TYPES.add(EAP_NOTIFICATION); 92 SUPPORTED_TYPES.add(EAP_NAK); 93 94 // supported EAP Method types 95 SUPPORTED_TYPES.add(EAP_TYPE_SIM); 96 SUPPORTED_TYPES.add(EAP_TYPE_AKA); 97 SUPPORTED_TYPES.add(EAP_TYPE_MSCHAP_V2); 98 SUPPORTED_TYPES.add(EAP_TYPE_AKA_PRIME); 99 SUPPORTED_TYPES.add(EAP_TYPE_TTLS); 100 } 101 102 @EapType public final int eapType; 103 public final byte[] eapTypeData; 104 105 public static final EapData NOTIFICATION_DATA = new EapData(EAP_NOTIFICATION, new byte[0]); 106 107 /** 108 * Constructs a new EapData instance. 109 * 110 * @param eapType the {@link EapType} for this EapData instance 111 * @param eapTypeData the Type-Data for this EapData instance 112 * @throws IllegalArgumentException if eapTypeData is null or if 113 * {@link EapData#isSupportedEapType} is false for the given eapType 114 */ EapData(@apType int eapType, @NonNull byte[] eapTypeData)115 public EapData(@EapType int eapType, @NonNull byte[] eapTypeData) { 116 this.eapType = eapType; 117 this.eapTypeData = eapTypeData; 118 119 validate(); 120 } 121 122 /** 123 * Gets the length of this EapData object. 124 * 125 * @return int for the number of bytes this EapData object represents 126 */ getLength()127 public int getLength() { 128 // length of byte-array + 1 (for 1B type field) 129 return eapTypeData.length + 1; 130 } 131 132 /** 133 * Returns whether this instance is equal to the given Object o. 134 * 135 * @param o the Object to be tested for equality 136 * @return true iff this instance is equal to the given o 137 */ 138 @Override equals(Object o)139 public boolean equals(Object o) { 140 if (this == o) { 141 return true; 142 } 143 if (o == null || !(o instanceof EapData)) { 144 return false; 145 } 146 EapData eapData = (EapData) o; 147 return eapType == eapData.eapType 148 && Arrays.equals(eapTypeData, eapData.eapTypeData); 149 } 150 151 /** 152 * Returns the hashCode value for this instance. 153 * 154 * @return the hashCode value for this instance 155 */ 156 @Override hashCode()157 public int hashCode() { 158 return Objects.hash(eapType, Arrays.hashCode(eapTypeData)); 159 } 160 161 /** 162 * Puts the byte-encoding for this EapData instance into the given ByteBuffer. 163 * 164 * @param b the ByteBuffer to write this EapData instance to 165 */ encodeToByteBuffer(ByteBuffer b)166 public void encodeToByteBuffer(ByteBuffer b) { 167 b.put((byte) eapType); 168 b.put(eapTypeData); 169 } 170 171 /** 172 * Returns whether the given eapType is a supported {@link EapType} value. 173 * 174 * @param eapType the value to be checked 175 * @return true iff the given eapType is a supported EAP Type 176 */ isSupportedEapType(int eapType)177 public static boolean isSupportedEapType(int eapType) { 178 return SUPPORTED_TYPES.contains(eapType); 179 } 180 validate()181 private void validate() { 182 if (this.eapTypeData == null) { 183 throw new IllegalArgumentException("EapTypeData byte[] must be non-null"); 184 } 185 if (!isSupportedEapType(this.eapType)) { 186 throw new IllegalArgumentException("eapType must be be a valid @EapType value"); 187 } 188 } 189 } 190