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