• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.libraries.entitlement;
18 
19 import static com.android.libraries.entitlement.eapaka.EapAkaResponse.respondToEapAkaChallenge;
20 
21 import android.content.Context;
22 import android.telephony.TelephonyManager;
23 import android.util.Log;
24 
25 import androidx.annotation.Nullable;
26 
27 import com.android.libraries.entitlement.eapaka.EapAkaApi;
28 import com.android.libraries.entitlement.eapaka.EapAkaChallenge;
29 
30 /**
31  * Some utility methods used in EAP-AKA authentication in service entitlement, and could be
32  * helpful to other apps.
33  */
34 public class EapAkaHelper {
35     private static final String TAG = "ServiceEntitlement";
36 
37     private final Context mContext;
38     private final int mSimSubscriptionId;
39 
EapAkaHelper(Context context, int simSubscriptionId)40     EapAkaHelper(Context context, int simSubscriptionId) {
41         mContext = context;
42         mSimSubscriptionId = simSubscriptionId;
43     }
44 
45     /**
46      * Factory method.
47      *
48      * @param context           context of application
49      * @param simSubscriptionId the subscroption ID of the carrier's SIM on device. This indicates
50      *                          which SIM to retrieve IMEI/IMSI from and perform EAP-AKA
51      *                          authentication with. See
52      *                          {@link android.telephony.SubscriptionManager}
53      *                          for how to get the subscroption ID.
54      */
getInstance(Context context, int simSubscriptionId)55     public static EapAkaHelper getInstance(Context context, int simSubscriptionId) {
56         return new EapAkaHelper(context, simSubscriptionId);
57     }
58 
59     /**
60      * Returns the root NAI for EAP-AKA authentication as per 3GPP TS 23.003 19.3.2, or
61      * {@code null} if failed. The result will be in the form:
62      *
63      * <p>{@code 0<IMSI>@nai.epc.mnc<MNC>.mcc<MCC>.3gppnetwork.org}
64      */
65     @Nullable
getEapAkaRootNai()66     public String getEapAkaRootNai() {
67         TelephonyManager telephonyManager =
68                 mContext.getSystemService(TelephonyManager.class)
69                         .createForSubscriptionId(mSimSubscriptionId);
70         return EapAkaApi.getImsiEap(
71                 telephonyManager.getSimOperator(), telephonyManager.getSubscriberId(), "nai.epc");
72     }
73 
74     /**
75      * Returns the EAP-AKA challenge response to the given EAP-AKA {@code challenge}, or
76      * {@code null} if failed.
77      *
78      * <p>Both the challange and response are base-64 encoded EAP-AKA message: refer to
79      * RFC 4187 Section 8.1 Message Format/RFC 3748 Session 4 EAP Packet Format.
80      *
81      * @deprecated use {@link getEapAkaResponse(String)} which additionally supports
82      * Synchronization-Failure case.
83      */
84     @Deprecated
85     @Nullable
getEapAkaChallengeResponse(String challenge)86     public String getEapAkaChallengeResponse(String challenge) {
87         EapAkaResponse eapAkaResponse = getEapAkaResponse(challenge);
88         return (eapAkaResponse == null)
89                 ? null
90                 : eapAkaResponse.response(); // Would be null on synchronization failure
91     }
92 
93     /**
94      * Returns the {@link EapAkaResponse} to the given EAP-AKA {@code challenge}, or
95      * {@code null} if failed.
96      *
97      * <p>Both the challange and response are base-64 encoded EAP-AKA message: refer to
98      * RFC 4187 Section 8.1 Message Format/RFC 3748 Session 4 EAP Packet Format.
99      */
100     @Nullable
getEapAkaResponse(String challenge)101     public EapAkaResponse getEapAkaResponse(String challenge) {
102         try {
103             EapAkaChallenge eapAkaChallenge = EapAkaChallenge.parseEapAkaChallenge(challenge);
104             com.android.libraries.entitlement.eapaka.EapAkaResponse eapAkaResponse =
105                     respondToEapAkaChallenge(
106                             mContext, mSimSubscriptionId, eapAkaChallenge, "nai.epc");
107             return new EapAkaResponse(
108                     eapAkaResponse.response(), eapAkaResponse.synchronizationFailureResponse());
109         } catch (ServiceEntitlementException e) {
110             Log.i(TAG, "Failed to generate EAP-AKA response", e);
111             return null;
112         }
113     }
114 
115     // Similar to .eapaka.EapAkaResponse but with simplfied API surface for external usage.
116     /** EAP-AKA response */
117     public static class EapAkaResponse {
118         // RFC 4187 Section 9.4 EAP-Response/AKA-Challenge
119         @Nullable private final String mResponse;
120         // RFC 4187 Section 9.6 EAP-Response/AKA-Synchronization-Failure
121         @Nullable private final String mSynchronizationFailureResponse;
122 
EapAkaResponse( @ullable String response, @Nullable String synchronizationFailureResponse)123         private EapAkaResponse(
124                 @Nullable String response, @Nullable String synchronizationFailureResponse) {
125             mResponse = response;
126             mSynchronizationFailureResponse = synchronizationFailureResponse;
127         }
128 
129         /**
130          * Returns EAP-Response/AKA-Challenge, if authentication success.
131          * Otherwise {@code null}.
132          */
133         @Nullable
response()134         public String response() {
135             return mResponse;
136         }
137 
138         /**
139          * Returns EAP-Response/AKA-Synchronization-Failure, if synchronization failure detected.
140          * Otherwise {@code null}.
141          */
142         @Nullable
synchronizationFailureResponse()143         public String synchronizationFailureResponse() {
144             return mSynchronizationFailureResponse;
145         }
146     }
147 }
148