1 /*
2  * Copyright (C) 2016 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.server.wifi.hotspot2.anqp.eap;
18 
19 import com.android.internal.annotations.VisibleForTesting;
20 
21 import java.net.ProtocolException;
22 import java.nio.BufferUnderflowException;
23 import java.nio.ByteBuffer;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Map;
28 import java.util.Set;
29 
30 /**
31  * An EAP Method part of the NAI Realm ANQP element, specified in
32  * IEEE802.11-2012 section 8.4.4.10, figure 8-420
33  *
34  * Format:
35  * | Length | EAP Method | Auth Param Count | Auth Param #1 (optional) | ....
36  *     1          1               1                 variable
37  */
38 public class EAPMethod {
39     private final int mEAPMethodID;
40     private final Map<Integer, Set<AuthParam>> mAuthParams;
41 
42     @VisibleForTesting
EAPMethod(int methodID, Map<Integer, Set<AuthParam>> authParams)43     public EAPMethod(int methodID, Map<Integer, Set<AuthParam>> authParams) {
44         mEAPMethodID = methodID;
45         mAuthParams = authParams;
46     }
47 
48     /**
49      * Parse a EAPMethod from the given buffer.
50      *
51      * @param payload The byte buffer to read from
52      * @return {@link EAPMethod}
53      * @throws ProtocolException
54      * @throws BufferUnderflowException
55      */
parse(ByteBuffer payload)56     public static EAPMethod parse(ByteBuffer payload) throws ProtocolException {
57         // Read and verify the length field.
58         int length = payload.get() & 0xFF;
59         if (length > payload.remaining()) {
60             throw new ProtocolException("Invalid data length: " + length);
61         }
62 
63         int methodID = payload.get() & 0xFF;
64         int authCount = payload.get() & 0xFF;
65         Map<Integer, Set<AuthParam>> authParams = new HashMap<>();
66         while (authCount > 0) {
67             addAuthParam(authParams, parseAuthParam(payload));
68             authCount--;
69         }
70         return new EAPMethod(methodID, authParams);
71     }
72 
73     /**
74      * Parse a AuthParam from the given buffer.
75      *
76      * Format:
77      * | Auth ID | Length | Value |
78      *      1         1    variable
79      *
80      * @param payload The byte buffer to read from
81      * @return {@link AuthParam}
82      * @throws BufferUnderflowException
83      * @throws ProtocolException
84      */
parseAuthParam(ByteBuffer payload)85     private static AuthParam parseAuthParam(ByteBuffer payload) throws ProtocolException {
86         int authID = payload.get() & 0xFF;
87         int length = payload.get() & 0xFF;
88         switch (authID) {
89             case AuthParam.PARAM_TYPE_EXPANDED_EAP_METHOD:
90                 return ExpandedEAPMethod.parse(payload, length, false);
91             case AuthParam.PARAM_TYPE_NON_EAP_INNER_AUTH_TYPE:
92                 return NonEAPInnerAuth.parse(payload, length);
93             case AuthParam.PARAM_TYPE_INNER_AUTH_EAP_METHOD_TYPE:
94                 return InnerAuthEAP.parse(payload, length);
95             case AuthParam.PARAM_TYPE_EXPANDED_INNER_EAP_METHOD:
96                 return ExpandedEAPMethod.parse(payload, length, true);
97             case AuthParam.PARAM_TYPE_CREDENTIAL_TYPE:
98                 return CredentialType.parse(payload, length, false);
99             case AuthParam.PARAM_TYPE_TUNNELED_EAP_METHOD_CREDENTIAL_TYPE:
100                 return CredentialType.parse(payload, length, true);
101             case AuthParam.PARAM_TYPE_VENDOR_SPECIFIC:
102                 return VendorSpecificAuth.parse(payload, length);
103             default:
104                 throw new ProtocolException("Unknow Auth Type ID: " + authID);
105         }
106     }
107 
108     /**
109      * Add an AuthParam to a map of authentication parameters.  It is possible to have
110      * multiple authentication parameters for the same type.
111      *
112      * @param paramsMap The authentication parameter map to add the new parameter to
113      * @param authParam The authentication parameter to add
114      */
addAuthParam(Map<Integer, Set<AuthParam>> paramsMap, AuthParam authParam)115     private static void addAuthParam(Map<Integer, Set<AuthParam>> paramsMap,
116             AuthParam authParam) {
117         Set<AuthParam> authParams = paramsMap.get(authParam.getAuthTypeID());
118         if (authParams == null) {
119             authParams = new HashSet<>();
120             paramsMap.put(authParam.getAuthTypeID(), authParams);
121         }
122         authParams.add(authParam);
123     }
124 
getAuthParams()125     public Map<Integer, Set<AuthParam>> getAuthParams() {
126         return Collections.unmodifiableMap(mAuthParams);
127     }
128 
getEAPMethodID()129     public int getEAPMethodID() {
130         return mEAPMethodID;
131     }
132 
133     @Override
equals(Object thatObject)134     public boolean equals(Object thatObject) {
135         if (thatObject == this) {
136             return true;
137         }
138         if (!(thatObject instanceof EAPMethod)) {
139             return false;
140         }
141         EAPMethod that = (EAPMethod) thatObject;
142         return mEAPMethodID == that.mEAPMethodID && mAuthParams.equals(that.mAuthParams);
143     }
144 
145     @Override
hashCode()146     public int hashCode() {
147         return mEAPMethodID * 31 + mAuthParams.hashCode();
148     }
149 
150     @Override
toString()151     public String toString() {
152         return "EAPMethod{mEAPMethodID=" + mEAPMethodID + " mAuthParams=" + mAuthParams + "}";
153     }
154 }
155