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 android.net.eap;
18 
19 import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
20 import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
21 import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
22 import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.SystemApi;
27 import android.telephony.Annotation.UiccAppType;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.internal.net.eap.message.EapData.EapMethod;
31 
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Map;
35 
36 /**
37  * EapSessionConfig represents a container for EAP method configuration.
38  *
39  * <p>The EAP authentication server decides which EAP method is used, so clients are encouraged to
40  * provide configs for several EAP methods.
41  *
42  * @hide
43  */
44 @SystemApi
45 public final class EapSessionConfig {
46     /** @hide */
47     @VisibleForTesting static final byte[] DEFAULT_IDENTITY = new byte[0];
48 
49     // IANA -> EapMethodConfig for that method
50     /** @hide */
51     public final Map<Integer, EapMethodConfig> eapConfigs;
52     /** @hide */
53     public final byte[] eapIdentity;
54 
55     /** @hide */
56     @VisibleForTesting
EapSessionConfig(Map<Integer, EapMethodConfig> eapConfigs, byte[] eapIdentity)57     public EapSessionConfig(Map<Integer, EapMethodConfig> eapConfigs, byte[] eapIdentity) {
58         this.eapConfigs = Collections.unmodifiableMap(eapConfigs);
59         this.eapIdentity = eapIdentity;
60     }
61 
62     /** Retrieves client's EAP Identity */
63     @NonNull
getEapIdentity()64     public byte[] getEapIdentity() {
65         return eapIdentity;
66     }
67 
68     /**
69      * Retrieves configuration for EAP SIM
70      *
71      * @return the configuration for EAP SIM, or null if it was not set
72      */
73     @Nullable
getEapSimConfig()74     public EapSimConfig getEapSimConfig() {
75         return (EapSimConfig) eapConfigs.get(EAP_TYPE_SIM);
76     }
77 
78     /**
79      * Retrieves configuration for EAP AKA
80      *
81      * @return the configuration for EAP AKA, or null if it was not set
82      */
83     @Nullable
getEapAkaConfig()84     public EapAkaConfig getEapAkaConfig() {
85         return (EapAkaConfig) eapConfigs.get(EAP_TYPE_AKA);
86     }
87 
88     /**
89      * Retrieves configuration for EAP AKA'
90      *
91      * @return the configuration for EAP AKA', or null if it was not set
92      */
93     @Nullable
getEapAkaPrimeConfig()94     public EapAkaPrimeConfig getEapAkaPrimeConfig() {
95         return (EapAkaPrimeConfig) eapConfigs.get(EAP_TYPE_AKA_PRIME);
96     }
97 
98     /**
99      * Retrieves configuration for EAP MSCHAPV2
100      *
101      * @return the configuration for EAP MSCHAPV2, or null if it was not set
102      */
103     @Nullable
getEapMsChapV2onfig()104     public EapMsChapV2Config getEapMsChapV2onfig() {
105         return (EapMsChapV2Config) eapConfigs.get(EAP_TYPE_MSCHAP_V2);
106     }
107 
108     /** This class can be used to incrementally construct an {@link EapSessionConfig}. */
109     public static final class Builder {
110         private final Map<Integer, EapMethodConfig> mEapConfigs;
111         private byte[] mEapIdentity;
112 
113         /** Constructs and returns a new Builder for constructing an {@link EapSessionConfig}. */
Builder()114         public Builder() {
115             mEapConfigs = new HashMap<>();
116             mEapIdentity = DEFAULT_IDENTITY;
117         }
118 
119         /**
120          * Sets the client's EAP Identity.
121          *
122          * @param eapIdentity byte[] representing the client's EAP Identity.
123          * @return Builder this, to facilitate chaining.
124          */
125         @NonNull
setEapIdentity(@onNull byte[] eapIdentity)126         public Builder setEapIdentity(@NonNull byte[] eapIdentity) {
127             this.mEapIdentity = eapIdentity.clone();
128             return this;
129         }
130 
131         /**
132          * Sets the configuration for EAP SIM.
133          *
134          * @param subId int the client's subId to be authenticated.
135          * @param apptype the {@link UiccAppType} apptype to be used for authentication.
136          * @return Builder this, to facilitate chaining.
137          */
138         @NonNull
setEapSimConfig(int subId, @UiccAppType int apptype)139         public Builder setEapSimConfig(int subId, @UiccAppType int apptype) {
140             mEapConfigs.put(EAP_TYPE_SIM, new EapSimConfig(subId, apptype));
141             return this;
142         }
143 
144         /**
145          * Sets the configuration for EAP AKA.
146          *
147          * @param subId int the client's subId to be authenticated.
148          * @param apptype the {@link UiccAppType} apptype to be used for authentication.
149          * @return Builder this, to facilitate chaining.
150          */
151         @NonNull
setEapAkaConfig(int subId, @UiccAppType int apptype)152         public Builder setEapAkaConfig(int subId, @UiccAppType int apptype) {
153             mEapConfigs.put(EAP_TYPE_AKA, new EapAkaConfig(subId, apptype));
154             return this;
155         }
156 
157         /**
158          * Sets the configuration for EAP AKA'.
159          *
160          * @param subId int the client's subId to be authenticated.
161          * @param apptype the {@link UiccAppType} apptype to be used for authentication.
162          * @param networkName String the network name to be used for authentication.
163          * @param allowMismatchedNetworkNames indicates whether the EAP library can ignore potential
164          *     mismatches between the given network name and that received in an EAP-AKA' session.
165          *     If false, mismatched network names will be handled as an Authentication Reject
166          *     message.
167          * @return Builder this, to facilitate chaining.
168          */
169         @NonNull
setEapAkaPrimeConfig( int subId, @UiccAppType int apptype, @NonNull String networkName, boolean allowMismatchedNetworkNames)170         public Builder setEapAkaPrimeConfig(
171                 int subId,
172                 @UiccAppType int apptype,
173                 @NonNull String networkName,
174                 boolean allowMismatchedNetworkNames) {
175             mEapConfigs.put(
176                     EAP_TYPE_AKA_PRIME,
177                     new EapAkaPrimeConfig(
178                             subId, apptype, networkName, allowMismatchedNetworkNames));
179             return this;
180         }
181 
182         /**
183          * Sets the configuration for EAP MSCHAPv2.
184          *
185          * @param username String the client account's username to be authenticated.
186          * @param password String the client account's password to be authenticated.
187          * @return Builder this, to faciliate chaining.
188          */
189         @NonNull
setEapMsChapV2Config(@onNull String username, @NonNull String password)190         public Builder setEapMsChapV2Config(@NonNull String username, @NonNull String password) {
191             mEapConfigs.put(EAP_TYPE_MSCHAP_V2, new EapMsChapV2Config(username, password));
192             return this;
193         }
194 
195         /**
196          * Constructs and returns an EapSessionConfig with the configurations applied to this
197          * Builder.
198          *
199          * @return the EapSessionConfig constructed by this Builder.
200          */
201         @NonNull
build()202         public EapSessionConfig build() {
203             if (mEapConfigs.isEmpty()) {
204                 throw new IllegalStateException("Must have at least one EAP method configured");
205             }
206 
207             return new EapSessionConfig(mEapConfigs, mEapIdentity);
208         }
209     }
210 
211     /**
212      * EapMethodConfig represents a generic EAP method configuration.
213      */
214     public abstract static class EapMethodConfig {
215         /** @hide */
216         @EapMethod public final int methodType;
217 
218         /** @hide */
EapMethodConfig(@apMethod int methodType)219         EapMethodConfig(@EapMethod int methodType) {
220             this.methodType = methodType;
221         }
222 
223         /**
224          * Retrieves the EAP method type
225          *
226          * @return the IANA-defined EAP method constant
227          */
getMethodType()228         public int getMethodType() {
229             return methodType;
230         }
231 
232         /**
233          * Check if this is EAP-only safe method.
234          *
235          * @return whether the method is EAP-only safe
236          *
237          * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998#section 4, for safe eap
238          * methods</a>
239          *
240          * @hide
241          */
isEapOnlySafeMethod()242         public boolean isEapOnlySafeMethod() {
243             return false;
244         }
245     }
246 
247     /**
248      * EapUiccConfig represents the configs needed for EAP methods that rely on UICC cards for
249      * authentication.
250      */
251     public abstract static class EapUiccConfig extends EapMethodConfig {
252         /** @hide */
253         public final int subId;
254         /** @hide */
255         public final int apptype;
256 
EapUiccConfig(@apMethod int methodType, int subId, @UiccAppType int apptype)257         private EapUiccConfig(@EapMethod int methodType, int subId, @UiccAppType int apptype) {
258             super(methodType);
259             this.subId = subId;
260             this.apptype = apptype;
261         }
262 
263         /**
264          * Retrieves the subId
265          *
266          * @return the subId
267          */
getSubId()268         public int getSubId() {
269             return subId;
270         }
271 
272         /**
273          * Retrieves the UICC app type
274          *
275          * @return the {@link UiccAppType} constant
276          */
getAppType()277         public int getAppType() {
278             return apptype;
279         }
280 
281         /** @hide */
282         @Override
isEapOnlySafeMethod()283         public boolean isEapOnlySafeMethod() {
284             return true;
285         }
286     }
287 
288     /**
289      * EapSimConfig represents the configs needed for an EAP SIM session.
290      */
291     public static class EapSimConfig extends EapUiccConfig {
292         /** @hide */
293         @VisibleForTesting
EapSimConfig(int subId, @UiccAppType int apptype)294         public EapSimConfig(int subId, @UiccAppType int apptype) {
295             super(EAP_TYPE_SIM, subId, apptype);
296         }
297     }
298 
299     /**
300      * EapAkaConfig represents the configs needed for an EAP AKA session.
301      */
302     public static class EapAkaConfig extends EapUiccConfig {
303         /** @hide */
304         @VisibleForTesting
EapAkaConfig(int subId, @UiccAppType int apptype)305         public EapAkaConfig(int subId, @UiccAppType int apptype) {
306             this(EAP_TYPE_AKA, subId, apptype);
307         }
308 
309         /** @hide */
EapAkaConfig(int methodType, int subId, @UiccAppType int apptype)310         EapAkaConfig(int methodType, int subId, @UiccAppType int apptype) {
311             super(methodType, subId, apptype);
312         }
313     }
314 
315     /**
316      * EapAkaPrimeConfig represents the configs needed for an EAP-AKA' session.
317      */
318     public static class EapAkaPrimeConfig extends EapAkaConfig {
319         /** @hide */
320         @NonNull public final String networkName;
321         /** @hide */
322         public final boolean allowMismatchedNetworkNames;
323 
324         /** @hide */
325         @VisibleForTesting
EapAkaPrimeConfig( int subId, @UiccAppType int apptype, @NonNull String networkName, boolean allowMismatchedNetworkNames)326         public EapAkaPrimeConfig(
327                 int subId,
328                 @UiccAppType int apptype,
329                 @NonNull String networkName,
330                 boolean allowMismatchedNetworkNames) {
331             super(EAP_TYPE_AKA_PRIME, subId, apptype);
332 
333             if (networkName == null) {
334                 throw new IllegalArgumentException("NetworkName was null");
335             }
336 
337             this.networkName = networkName;
338             this.allowMismatchedNetworkNames = allowMismatchedNetworkNames;
339         }
340 
341         /**
342          * Retrieves the UICC app type
343          *
344          * @return the {@link UiccAppType} constant
345          */
346         @NonNull
getNetworkName()347         public String getNetworkName() {
348             return networkName;
349         }
350 
351         /**
352          * Checks if mismatched network names are allowed
353          *
354          * @return whether network name mismatches are allowed
355          */
allowsMismatchedNetworkNames()356         public boolean allowsMismatchedNetworkNames() {
357             return allowMismatchedNetworkNames;
358         }
359     }
360 
361     /**
362      * EapMsChapV2Config represents the configs needed for an EAP MSCHAPv2 session.
363      */
364     public static class EapMsChapV2Config extends EapMethodConfig {
365         /** @hide */
366         @NonNull public final String username;
367         /** @hide */
368         @NonNull public final String password;
369 
370         /** @hide */
371         @VisibleForTesting
EapMsChapV2Config(String username, String password)372         public EapMsChapV2Config(String username, String password) {
373             super(EAP_TYPE_MSCHAP_V2);
374 
375             if (username == null || password == null) {
376                 throw new IllegalArgumentException("Username or password was null");
377             }
378 
379             this.username = username;
380             this.password = password;
381         }
382 
383         /**
384          * Retrieves the username
385          *
386          * @return the username to be used by MSCHAPV2
387          */
388         @NonNull
getUsername()389         public String getUsername() {
390             return username;
391         }
392 
393         /**
394          * Retrieves the password
395          *
396          * @return the password to be used by MSCHAPV2
397          */
398         @NonNull
getPassword()399         public String getPassword() {
400             return password;
401         }
402     }
403 
404     /**
405      * Checks if all the methods in the session are EAP-only safe
406      *
407      * @return whether all the methods in the session are EAP-only safe
408      *
409      * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998#section 4, for safe eap
410      * methods</a>
411      *
412      * @hide
413      */
areAllMethodsEapOnlySafe()414     public boolean areAllMethodsEapOnlySafe() {
415         for(Map.Entry<Integer, EapMethodConfig> eapConfigsEntry : eapConfigs.entrySet()) {
416             if (!eapConfigsEntry.getValue().isEapOnlySafeMethod()) {
417                 return false;
418             }
419         }
420 
421         return true;
422     }
423 }
424