1 /*
2  * Copyright (C) 2020 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 package com.android.internal.net.ipsec.ike.ike3gpp;
17 
18 import static android.net.ipsec.ike.IkeManager.getIkeLog;
19 
20 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_GENERIC_INFO;
21 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_IKE_AUTH;
22 
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.net.ipsec.ike.exceptions.InvalidSyntaxException;
26 import android.net.ipsec.ike.ike3gpp.Ike3gppExtension;
27 import android.net.ipsec.ike.ike3gpp.Ike3gppExtension.Ike3gppDataListener;
28 import android.util.ArraySet;
29 
30 import com.android.internal.net.ipsec.ike.message.IkeMessage;
31 import com.android.internal.net.ipsec.ike.message.IkePayload;
32 
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.Objects;
36 import java.util.Set;
37 import java.util.concurrent.Executor;
38 
39 /**
40  * Ike3gppExtensionExchange contains the implementation for 3GPP-specific functionality in IKEv2.
41  */
42 public class Ike3gppExtensionExchange implements AutoCloseable {
43     private static final String TAG = Ike3gppExtensionExchange.class.getSimpleName();
44 
45     private static final Set<Ike3gppDataListener> REGISTERED_LISTENERS =
46             Collections.synchronizedSet(new ArraySet<>());
47 
48     /**
49      * Indicates that the caller must wait the specified time before attempting to open an IKE
50      * Session with the peer.
51      *
52      * <p>Note that this is not an IANA-specified value.
53      *
54      * <p>Must be accompanied by an Error-Notify(ERROR_TYPE_NO_APN_SUBSCRIPTION) or
55      * Error-Notify(ERROR_TYPE_NETWORK_FAILURE); otherwise, the payload will be logged and ignored.
56      */
57     public static final int NOTIFY_TYPE_BACKOFF_TIMER = 41041;
58 
59     /**
60      * Indicates that the UE supports N1 Mode during 5G SA ePDG tunnel setup.
61      *
62      * <p>Note that this is not an IANA-specified value.
63      *
64      * <p>A PDU session ID will be included to indicate the PDU session associated with the IKEv2
65      * SA.
66      *
67      * <p>See TS 124 302 - Universal Mobile Telecommunications System (UMTS); LTE; 5G; Access to the
68      * 3GPP Evolved Packet Core (EPC) via non-3GPP access networks (Section 8.2.9.15) for more
69      * details.
70      */
71     public static final int NOTIFY_TYPE_N1_MODE_CAPABILITY = 51015;
72 
73     /**
74      * Used for reporting the S-NSSAI from the server to the UE for the reported PDU Session ID.
75      *
76      * <p>Note that this is not an IANA-specified value.
77      *
78      * <p>This Payload will only be sent from the server to the user device after {@link
79      * NOTIFY_TYPE_N1_MODE_CAPABILITY} is sent during the IKE_AUTH exchange.
80      *
81      * <p>See TS 124 302 - Universal Mobile Telecommunications System (UMTS); LTE; 5G; Access to the
82      * 3GPP Evolved Packet Core (EPC) via non-3GPP access networks (Section 8.2.9.16) for more
83      * details.
84      */
85     public static final int NOTIFY_TYPE_N1_MODE_INFORMATION = 51115;
86 
87     /**
88      * Used to share the device idenity (IMEI/IMEISV) with the carrier network.
89      *
90      * <p>Note that this is not an IANA-specified value.
91      *
92      * <p>See TS 124 302 - Universal Mobile Telecommunications System (UMTS); LTE; 5G; Access to the
93      * 3GPP Evolved Packet Core (EPC) via non-3GPP access networks (Section 8.2.9.2) for more
94      * details.
95      */
96     public static final int NOTIFY_TYPE_DEVICE_IDENTITY = 41101;
97 
98     @Nullable private final Ike3gppExtension mIke3gppExtension;
99     @NonNull private final Executor mUserCbExecutor;
100     @Nullable private final Ike3gppIkeAuth mIke3gppIkeAuth;
101     @Nullable private final Ike3gppIkeInfo mIke3gppIkeInfo;
102 
103     /**
104      * Initializes an Ike3gppExtensionExchange.
105      *
106      * <p>If ike3gppExtension is null, no 3GPP functionality will be enabled.
107      */
Ike3gppExtensionExchange( @ullable Ike3gppExtension ike3gppExtension, @NonNull Executor userCbExecutor)108     public Ike3gppExtensionExchange(
109             @Nullable Ike3gppExtension ike3gppExtension, @NonNull Executor userCbExecutor) {
110         mIke3gppExtension = ike3gppExtension;
111         mUserCbExecutor = Objects.requireNonNull(userCbExecutor, "userCbExecutor must not be null");
112 
113         if (mIke3gppExtension != null) {
114             mIke3gppIkeAuth = new Ike3gppIkeAuth(mIke3gppExtension, mUserCbExecutor);
115             mIke3gppIkeInfo = new Ike3gppIkeInfo(mIke3gppExtension, mUserCbExecutor);
116 
117             if (!REGISTERED_LISTENERS.add(ike3gppExtension.getIke3gppDataListener())) {
118                 throw new IllegalArgumentException(
119                         "Ike3gppDataListener must be unique for each IkeSession");
120             }
121 
122             logd("IKE 3GPP Extension enabled: " + mIke3gppExtension.getIke3gppParams());
123         } else {
124             mIke3gppIkeAuth = null;
125             mIke3gppIkeInfo = null;
126         }
127     }
128 
129     @Override
close()130     public void close() {
131         if (mIke3gppExtension == null) return;
132 
133         REGISTERED_LISTENERS.remove(mIke3gppExtension.getIke3gppDataListener());
134     }
135 
136     /**
137      * Gets the 3GPP-specific Information Response IkePayloads for the specified exchangeSubtype.
138      */
getResponsePayloads( int exchangeSubtype, List<IkePayload> ike3gppRequestPayloads)139     public List<IkePayload> getResponsePayloads(
140             int exchangeSubtype, List<IkePayload> ike3gppRequestPayloads) {
141         if (mIke3gppExtension == null) return Collections.EMPTY_LIST;
142 
143         switch (exchangeSubtype) {
144             case IKE_EXCHANGE_SUBTYPE_GENERIC_INFO:
145                 return mIke3gppIkeInfo.getResponsePayloads(ike3gppRequestPayloads);
146             default:
147                 // No 3GPP-specific behavior for this exchange subtype
148                 return Collections.EMPTY_LIST;
149         }
150     }
151 
152     /** Gets the 3GPP-specific Request IkePayloads for the specified exchangeSubtype. */
getRequestPayloads(int exchangeSubtype)153     public List<IkePayload> getRequestPayloads(int exchangeSubtype) {
154         if (mIke3gppExtension == null) return Collections.EMPTY_LIST;
155 
156         switch (exchangeSubtype) {
157             case IKE_EXCHANGE_SUBTYPE_IKE_AUTH:
158                 return mIke3gppIkeAuth.getRequestPayloads();
159             default:
160                 // No 3GPP-specific behavior for this exchange subtype
161                 String exchangeSubtypeString =
162                         IkeMessage.getIkeExchangeSubTypeString(exchangeSubtype);
163                 logw("No 3GPP request payloads added for: " + exchangeSubtypeString);
164                 return Collections.EMPTY_LIST;
165         }
166     }
167 
168     /**
169      * Provides a list of 3GPP payloads to add in an outbound AUTH req based on peer authentication
170      * status.
171      */
getRequestPayloadsInEap(boolean serverAuthenticated)172     public List<IkePayload> getRequestPayloadsInEap(boolean serverAuthenticated) {
173         if (mIke3gppExtension == null) return Collections.EMPTY_LIST;
174         return mIke3gppIkeAuth.getRequestPayloadsInEap(serverAuthenticated);
175     }
176 
177     /**
178      * Returns a list of 3GPP-specific Response Payloads from the given list that are valid for the
179      * specified exchangeSubtype.
180      */
extract3gppResponsePayloads( int exchangeSubtype, List<IkePayload> payloads)181     public List<IkePayload> extract3gppResponsePayloads(
182             int exchangeSubtype, List<IkePayload> payloads) {
183         if (mIke3gppExtension == null) return Collections.EMPTY_LIST;
184 
185         switch (exchangeSubtype) {
186             case IKE_EXCHANGE_SUBTYPE_IKE_AUTH:
187                 return mIke3gppIkeAuth.extract3gppResponsePayloads(payloads);
188             default:
189                 // No 3GPP-specific behavior for this exchange subtype
190                 String exchangeSubtypeString =
191                         IkeMessage.getIkeExchangeSubTypeString(exchangeSubtype);
192                 logw("No 3GPP response payloads expected for: " + exchangeSubtypeString);
193                 return Collections.EMPTY_LIST;
194         }
195     }
196 
197     /**
198      * Handles the provided Response IkePayloads for the specified exchangeSubtype.
199      *
200      * <p>If the caller needs to be notified of received Ike3gppData, the configured
201      * Ike3gppDataListener will be invoked.
202      */
handle3gppResponsePayloads(int exchangeSubtype, List<IkePayload> ike3gppPayloads)203     public void handle3gppResponsePayloads(int exchangeSubtype, List<IkePayload> ike3gppPayloads)
204             throws InvalidSyntaxException {
205         if (mIke3gppExtension == null || ike3gppPayloads.isEmpty()) return;
206 
207         switch (exchangeSubtype) {
208             case IKE_EXCHANGE_SUBTYPE_IKE_AUTH:
209                 mIke3gppIkeAuth.handleAuthResp(ike3gppPayloads);
210                 break;
211             default:
212                 // No 3GPP-specific behavior for this exchange subtype
213                 String exchangeSubtypeString =
214                         IkeMessage.getIkeExchangeSubTypeString(exchangeSubtype);
215                 logw("Received unexpected 3GPP payloads in: " + exchangeSubtypeString);
216         }
217     }
218 
logw(String msg)219     private void logw(String msg) {
220         getIkeLog().w(TAG, msg);
221     }
222 
logd(String msg)223     private void logd(String msg) {
224         getIkeLog().d(TAG, msg);
225     }
226 }
227