• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.internal.net.ipsec.ike;
17 
18 import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION;
19 import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE;
20 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
21 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_NONE;
22 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_UDP;
23 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
24 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV4;
25 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV6;
26 import static android.net.ipsec.ike.IkeSessionParams.IKE_NATT_KEEPALIVE_DELAY_SEC_MAX;
27 import static android.net.ipsec.ike.IkeSessionParams.IKE_NATT_KEEPALIVE_DELAY_SEC_MIN;
28 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH;
29 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_INITIAL_CONTACT;
30 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
31 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_REKEY_MOBILITY;
32 import static android.net.ipsec.ike.IkeSessionParams.NATT_KEEPALIVE_INTERVAL_AUTO;
33 import static android.net.ipsec.ike.exceptions.IkeException.wrapAsIkeException;
34 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_CHILD_SA_NOT_FOUND;
35 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SYNTAX;
36 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS;
37 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
38 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ErrorType;
39 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
40 
41 import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_TYPE_REPLY;
42 import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_INFORMATIONAL;
43 import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_OK;
44 import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_PARTIAL;
45 import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_PROTECTED_ERROR;
46 import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_UNPROTECTED_ERROR;
47 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_CREATE_CHILD;
48 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_DELETE_CHILD;
49 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_DELETE_IKE;
50 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_GENERIC_INFO;
51 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_IKE_AUTH;
52 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_IKE_INIT;
53 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_INVALID;
54 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_REKEY_CHILD;
55 import static com.android.internal.net.ipsec.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_REKEY_IKE;
56 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_COOKIE;
57 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_COOKIE2;
58 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_EAP_ONLY_AUTHENTICATION;
59 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED;
60 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_INITIAL_CONTACT;
61 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_MOBIKE_SUPPORTED;
62 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP;
63 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP;
64 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA;
65 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS;
66 import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_UPDATE_SA_ADDRESSES;
67 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_AUTH;
68 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_CP;
69 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_DELETE;
70 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_EAP;
71 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NOTIFY;
72 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_SA;
73 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_TS_INITIATOR;
74 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_TS_RESPONDER;
75 import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_VENDOR;
76 import static com.android.internal.net.ipsec.ike.net.IkeConnectionController.NAT_DETECTED;
77 import static com.android.internal.net.ipsec.ike.net.IkeConnectionController.NAT_TRAVERSAL_SUPPORT_NOT_CHECKED;
78 import static com.android.internal.net.ipsec.ike.net.IkeConnectionController.NAT_TRAVERSAL_UNSUPPORTED;
79 import static com.android.internal.net.ipsec.ike.utils.IkeAlarm.IkeAlarmConfig;
80 import static com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver.ACTION_DELETE_CHILD;
81 import static com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver.ACTION_DELETE_IKE;
82 import static com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver.ACTION_DPD;
83 import static com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver.ACTION_KEEPALIVE;
84 import static com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver.ACTION_REKEY_CHILD;
85 import static com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver.ACTION_REKEY_IKE;
86 
87 import android.annotation.NonNull;
88 import android.annotation.Nullable;
89 import android.app.AlarmManager;
90 import android.app.PendingIntent;
91 import android.content.Context;
92 import android.content.IntentFilter;
93 import android.net.ConnectivityManager;
94 import android.net.IpSecManager;
95 import android.net.IpSecManager.ResourceUnavailableException;
96 import android.net.IpSecManager.SpiUnavailableException;
97 import android.net.IpSecManager.UdpEncapsulationSocket;
98 import android.net.Network;
99 import android.net.TrafficStats;
100 import android.net.eap.EapInfo;
101 import android.net.eap.EapSessionConfig;
102 import android.net.ipsec.ike.ChildSessionCallback;
103 import android.net.ipsec.ike.ChildSessionParams;
104 import android.net.ipsec.ike.IkeManager;
105 import android.net.ipsec.ike.IkeSaProposal;
106 import android.net.ipsec.ike.IkeSessionCallback;
107 import android.net.ipsec.ike.IkeSessionConfiguration;
108 import android.net.ipsec.ike.IkeSessionConnectionInfo;
109 import android.net.ipsec.ike.IkeSessionParams;
110 import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig;
111 import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig;
112 import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig;
113 import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
114 import android.net.ipsec.ike.TransportModeChildSessionParams;
115 import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
116 import android.net.ipsec.ike.exceptions.IkeException;
117 import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
118 import android.net.ipsec.ike.exceptions.IkeProtocolException;
119 import android.net.ipsec.ike.exceptions.InvalidKeException;
120 import android.net.ipsec.ike.exceptions.InvalidSyntaxException;
121 import android.net.ipsec.ike.exceptions.NoValidProposalChosenException;
122 import android.net.ipsec.ike.exceptions.UnsupportedCriticalPayloadException;
123 import android.os.Bundle;
124 import android.os.Handler;
125 import android.os.Looper;
126 import android.os.Message;
127 import android.os.PowerManager;
128 import android.os.Process;
129 import android.util.LongSparseArray;
130 import android.util.Pair;
131 import android.util.SparseArray;
132 
133 import com.android.internal.annotations.GuardedBy;
134 import com.android.internal.annotations.VisibleForTesting;
135 import com.android.internal.net.eap.EapAuthenticator;
136 import com.android.internal.net.eap.EapResult;
137 import com.android.internal.net.eap.IEapCallback;
138 import com.android.internal.net.ipsec.ike.ChildSessionStateMachine.CreateChildSaHelper;
139 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
140 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.IkeLocalRequest;
141 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
142 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequestFactory;
143 import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
144 import com.android.internal.net.ipsec.ike.SaRecord.SaLifetimeAlarmScheduler;
145 import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
146 import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
147 import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
148 import com.android.internal.net.ipsec.ike.ike3gpp.Ike3gppExtensionExchange;
149 import com.android.internal.net.ipsec.ike.message.IkeAuthDigitalSignPayload;
150 import com.android.internal.net.ipsec.ike.message.IkeAuthPayload;
151 import com.android.internal.net.ipsec.ike.message.IkeAuthPskPayload;
152 import com.android.internal.net.ipsec.ike.message.IkeCertPayload;
153 import com.android.internal.net.ipsec.ike.message.IkeCertX509CertPayload;
154 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload;
155 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
156 import com.android.internal.net.ipsec.ike.message.IkeDeletePayload;
157 import com.android.internal.net.ipsec.ike.message.IkeEapPayload;
158 import com.android.internal.net.ipsec.ike.message.IkeHeader;
159 import com.android.internal.net.ipsec.ike.message.IkeHeader.ExchangeType;
160 import com.android.internal.net.ipsec.ike.message.IkeIdPayload;
161 import com.android.internal.net.ipsec.ike.message.IkeInformationalPayload;
162 import com.android.internal.net.ipsec.ike.message.IkeKePayload;
163 import com.android.internal.net.ipsec.ike.message.IkeMessage;
164 import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResult;
165 import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultError;
166 import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultOk;
167 import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultPartial;
168 import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultProtectedError;
169 import com.android.internal.net.ipsec.ike.message.IkeNoncePayload;
170 import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload;
171 import com.android.internal.net.ipsec.ike.message.IkePayload;
172 import com.android.internal.net.ipsec.ike.message.IkeSaPayload;
173 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IkeProposal;
174 import com.android.internal.net.ipsec.ike.message.IkeVendorPayload;
175 import com.android.internal.net.ipsec.ike.net.IkeConnectionController;
176 import com.android.internal.net.ipsec.ike.shim.IIkeSessionStateMachineShim;
177 import com.android.internal.net.ipsec.ike.shim.ShimUtils;
178 import com.android.internal.net.ipsec.ike.utils.IkeAlarm;
179 import com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver;
180 import com.android.internal.net.ipsec.ike.utils.IkeSecurityParameterIndex;
181 import com.android.internal.net.ipsec.ike.utils.IkeSpiGenerator;
182 import com.android.internal.net.ipsec.ike.utils.IpSecSpiGenerator;
183 import com.android.internal.net.ipsec.ike.utils.RandomnessFactory;
184 import com.android.internal.net.ipsec.ike.utils.Retransmitter;
185 import com.android.internal.util.State;
186 import com.android.modules.utils.build.SdkLevel;
187 
188 import java.io.IOException;
189 import java.net.Inet4Address;
190 import java.net.InetAddress;
191 import java.net.InetSocketAddress;
192 import java.nio.ByteBuffer;
193 import java.security.GeneralSecurityException;
194 import java.security.cert.TrustAnchor;
195 import java.security.cert.X509Certificate;
196 import java.util.ArrayList;
197 import java.util.Arrays;
198 import java.util.Collections;
199 import java.util.HashMap;
200 import java.util.HashSet;
201 import java.util.LinkedList;
202 import java.util.List;
203 import java.util.Objects;
204 import java.util.Set;
205 import java.util.concurrent.Executor;
206 import java.util.concurrent.TimeUnit;
207 import java.util.concurrent.atomic.AtomicInteger;
208 
209 /**
210  * IkeSessionStateMachine tracks states and manages exchanges of this IKE session.
211  *
212  * <p>IkeSessionStateMachine has two types of states. One type are states where there is no ongoing
213  * procedure affecting IKE session (non-procedure state), including Initial, Idle and Receiving. All
214  * other states are "procedure" states which are named as follows:
215  *
216  * <pre>
217  * State Name = [Procedure Type] + [Exchange Initiator] + [Exchange Type].
218  * - An IKE procedure consists of one or two IKE exchanges:
219  *      Procedure Type = {CreateIke | DeleteIke | Info | RekeyIke | SimulRekeyIke}.
220  * - Exchange Initiator indicates whether local or remote peer is the exchange initiator:
221  *      Exchange Initiator = {Local | Remote}
222  * - Exchange type defines the function of this exchange. To make it more descriptive, we separate
223  *      Delete Exchange from generic Informational Exchange:
224  *      Exchange Type = {IkeInit | IkeAuth | Create | Delete | Info}
225  * </pre>
226  */
227 public class IkeSessionStateMachine extends AbstractSessionStateMachine
228         implements IkeConnectionController.Callback,
229                 IkeSocket.Callback,
230                 IIkeSessionStateMachineShim {
231     // Package private
232     static final String TAG = "IkeSessionStateMachine";
233 
234     // "192.0.2.0" is selected from RFC5737, "IPv4 Address Blocks Reserved for Documentation"
235     private static final InetAddress FORCE_ENCAP_FAKE_LOCAL_ADDRESS_IPV4 =
236             new InetSocketAddress("192.0.2.0", 0).getAddress();
237     // "001:DB8::" is selected from RFC3849, "IPv6 Address Prefix Reserved for Documentation"
238     private static final InetAddress FORCE_ENCAP_FAKE_LOCAL_ADDRESS_IPV6 =
239             new InetSocketAddress("2001:DB8::", 0).getAddress();
240 
241     @VisibleForTesting static final String BUSY_WAKE_LOCK_TAG = "mBusyWakeLock";
242 
243     // TODO: b/140579254 Allow users to configure fragment size.
244 
245     private static final HashMap<Context, Set<IkeSessionStateMachine>> sContextToIkeSmMap =
246             new HashMap<>();
247 
248     /** Alarm receiver that will be shared by all IkeSessionStateMachine */
249     private static final IkeAlarmReceiver sIkeAlarmReceiver = new IkeAlarmReceiver();
250 
251     /** Intent filter for all Intents that should be received by sIkeAlarmReceiver */
252     // The only read/write operation is in a static block which is thread safe.
253     private static final IntentFilter sIntentFilter = new IntentFilter();
254 
255     static {
256         sIntentFilter.addAction(ACTION_DELETE_CHILD);
257         sIntentFilter.addAction(ACTION_DELETE_IKE);
258         sIntentFilter.addAction(ACTION_DPD);
259         sIntentFilter.addAction(ACTION_REKEY_CHILD);
260         sIntentFilter.addAction(ACTION_REKEY_IKE);
261         sIntentFilter.addAction(ACTION_KEEPALIVE);
262     }
263 
264     private static final AtomicInteger sIkeSessionIdGenerator = new AtomicInteger();
265 
266     // Bundle key for remote IKE SPI. Package private
267     @VisibleForTesting static final String BUNDLE_KEY_IKE_REMOTE_SPI = "BUNDLE_KEY_IKE_REMOTE_SPI";
268     // Bundle key for remote Child SPI. Package private
269     @VisibleForTesting
270     static final String BUNDLE_KEY_CHILD_REMOTE_SPI = "BUNDLE_KEY_CHILD_REMOTE_SPI";
271 
272     // Default fragment size in bytes.
273     @VisibleForTesting static final int DEFAULT_FRAGMENT_SIZE = 1280;
274 
275     // Close IKE Session when all responses during this time were TEMPORARY_FAILURE(s). This
276     // indicates that something has gone wrong, and we are out of sync.
277     @VisibleForTesting
278     static final long TEMP_FAILURE_RETRY_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(5L);
279 
280     /** Package private signals accessible for testing code. */
281     private static final int CMD_GENERAL_BASE = CMD_PRIVATE_BASE;
282 
283     /** Receive encoded IKE packet on IkeSessionStateMachine. */
284     static final int CMD_RECEIVE_IKE_PACKET = CMD_GENERAL_BASE + 1;
285     /** Receive encoded IKE packet with unrecognized IKE SPI on IkeSessionStateMachine. */
286     static final int CMD_RECEIVE_PACKET_INVALID_IKE_SPI = CMD_GENERAL_BASE + 2;
287     /** Receive an remote request for a Child procedure. */
288     static final int CMD_RECEIVE_REQUEST_FOR_CHILD = CMD_GENERAL_BASE + 3;
289     /** Receive payloads from Child Session for building an outbound IKE message. */
290     static final int CMD_OUTBOUND_CHILD_PAYLOADS_READY = CMD_GENERAL_BASE + 4;
291     /** A Child Session has finished its procedure. */
292     static final int CMD_CHILD_PROCEDURE_FINISHED = CMD_GENERAL_BASE + 5;
293     /** Send request/response payloads to ChildSessionStateMachine for further processing. */
294     static final int CMD_HANDLE_FIRST_CHILD_NEGOTIATION = CMD_GENERAL_BASE + 6;
295     /** Receive a local request to execute from the scheduler */
296     static final int CMD_EXECUTE_LOCAL_REQ = CMD_GENERAL_BASE + 7;
297     /** Trigger a retransmission. */
298     public static final int CMD_RETRANSMIT = CMD_GENERAL_BASE + 8;
299     /** Send EAP request payloads to EapAuthenticator for further processing. */
300     static final int CMD_EAP_START_EAP_AUTH = CMD_GENERAL_BASE + 9;
301     /** Send the outbound IKE-wrapped EAP-Response message. */
302     static final int CMD_EAP_OUTBOUND_MSG_READY = CMD_GENERAL_BASE + 10;
303     /** Proxy to IkeSessionStateMachine handler to notify of errors */
304     static final int CMD_EAP_ERRORED = CMD_GENERAL_BASE + 11;
305     /** Proxy to IkeSessionStateMachine handler to notify of failures */
306     static final int CMD_EAP_FAILED = CMD_GENERAL_BASE + 12;
307     /** Proxy to IkeSessionStateMachine handler to notify of success, to continue to post-auth */
308     static final int CMD_EAP_FINISH_EAP_AUTH = CMD_GENERAL_BASE + 14;
309     /** Alarm goes off for a scheduled event, check {@link Message.arg2} for event type */
310     static final int CMD_ALARM_FIRED = CMD_GENERAL_BASE + 15;
311     /** Send keepalive packet */
312     static final int CMD_SEND_KEEPALIVE = CMD_GENERAL_BASE + 16;
313     /**
314      * Update the Session's underlying Network
315      * obj = NetworkParams : params containing network, IP version, encap type and keepalive delay.
316      **/
317     static final int CMD_SET_NETWORK = CMD_GENERAL_BASE + 17;
318     /**
319      * Proxy to IkeSessionStateMachine handler to notify of the IKE fatal error hit in a Child
320      * procedure
321      */
322     static final int CMD_IKE_FATAL_ERROR_FROM_CHILD = CMD_GENERAL_BASE + 18;
323     /**
324      * Set the underpinned network
325      * obj = Network : the underpinned network
326      */
327     static final int CMD_SET_UNDERPINNED_NETWORK = CMD_GENERAL_BASE + 19;
328     /** Force state machine to a target state for testing purposes. */
329     static final int CMD_FORCE_TRANSITION = CMD_GENERAL_BASE + 99;
330 
331     static final int CMD_IKE_LOCAL_REQUEST_BASE = CMD_GENERAL_BASE + CMD_CATEGORY_SIZE;
332     static final int CMD_LOCAL_REQUEST_CREATE_IKE = CMD_IKE_LOCAL_REQUEST_BASE + 1;
333     static final int CMD_LOCAL_REQUEST_DELETE_IKE = CMD_IKE_LOCAL_REQUEST_BASE + 2;
334     static final int CMD_LOCAL_REQUEST_REKEY_IKE = CMD_IKE_LOCAL_REQUEST_BASE + 3;
335     static final int CMD_LOCAL_REQUEST_INFO = CMD_IKE_LOCAL_REQUEST_BASE + 4;
336     static final int CMD_LOCAL_REQUEST_DPD = CMD_IKE_LOCAL_REQUEST_BASE + 5;
337     static final int CMD_LOCAL_REQUEST_MOBIKE = CMD_IKE_LOCAL_REQUEST_BASE + 6;
338 
339     private static final SparseArray<String> CMD_TO_STR;
340 
341     static {
342         CMD_TO_STR = new SparseArray<>();
CMD_TO_STR.put(CMD_RECEIVE_IKE_PACKET, "Rcv packet")343         CMD_TO_STR.put(CMD_RECEIVE_IKE_PACKET, "Rcv packet");
CMD_TO_STR.put(CMD_RECEIVE_PACKET_INVALID_IKE_SPI, "Rcv invalid IKE SPI")344         CMD_TO_STR.put(CMD_RECEIVE_PACKET_INVALID_IKE_SPI, "Rcv invalid IKE SPI");
CMD_TO_STR.put(CMD_RECEIVE_REQUEST_FOR_CHILD, "Rcv Child request")345         CMD_TO_STR.put(CMD_RECEIVE_REQUEST_FOR_CHILD, "Rcv Child request");
CMD_TO_STR.put(CMD_OUTBOUND_CHILD_PAYLOADS_READY, "Out child payloads ready")346         CMD_TO_STR.put(CMD_OUTBOUND_CHILD_PAYLOADS_READY, "Out child payloads ready");
CMD_TO_STR.put(CMD_CHILD_PROCEDURE_FINISHED, "Child procedure finished")347         CMD_TO_STR.put(CMD_CHILD_PROCEDURE_FINISHED, "Child procedure finished");
CMD_TO_STR.put(CMD_HANDLE_FIRST_CHILD_NEGOTIATION, "Negotiate first Child")348         CMD_TO_STR.put(CMD_HANDLE_FIRST_CHILD_NEGOTIATION, "Negotiate first Child");
CMD_TO_STR.put(CMD_EXECUTE_LOCAL_REQ, "Execute local request")349         CMD_TO_STR.put(CMD_EXECUTE_LOCAL_REQ, "Execute local request");
CMD_TO_STR.put(CMD_RETRANSMIT, "Retransmit")350         CMD_TO_STR.put(CMD_RETRANSMIT, "Retransmit");
CMD_TO_STR.put(CMD_EAP_START_EAP_AUTH, "Start EAP")351         CMD_TO_STR.put(CMD_EAP_START_EAP_AUTH, "Start EAP");
CMD_TO_STR.put(CMD_EAP_OUTBOUND_MSG_READY, "EAP outbound msg ready")352         CMD_TO_STR.put(CMD_EAP_OUTBOUND_MSG_READY, "EAP outbound msg ready");
CMD_TO_STR.put(CMD_EAP_ERRORED, "EAP errored")353         CMD_TO_STR.put(CMD_EAP_ERRORED, "EAP errored");
CMD_TO_STR.put(CMD_EAP_FAILED, "EAP failed")354         CMD_TO_STR.put(CMD_EAP_FAILED, "EAP failed");
CMD_TO_STR.put(CMD_EAP_FINISH_EAP_AUTH, "Finish EAP")355         CMD_TO_STR.put(CMD_EAP_FINISH_EAP_AUTH, "Finish EAP");
CMD_TO_STR.put(CMD_ALARM_FIRED, "Alarm Fired")356         CMD_TO_STR.put(CMD_ALARM_FIRED, "Alarm Fired");
CMD_TO_STR.put(CMD_SET_NETWORK, "Update underlying Network")357         CMD_TO_STR.put(CMD_SET_NETWORK, "Update underlying Network");
CMD_TO_STR.put(CMD_SET_UNDERPINNED_NETWORK, "Set underpinned Network")358         CMD_TO_STR.put(CMD_SET_UNDERPINNED_NETWORK, "Set underpinned Network");
CMD_TO_STR.put(CMD_IKE_FATAL_ERROR_FROM_CHILD, "IKE fatal error from Child")359         CMD_TO_STR.put(CMD_IKE_FATAL_ERROR_FROM_CHILD, "IKE fatal error from Child");
CMD_TO_STR.put(CMD_LOCAL_REQUEST_CREATE_IKE, "Create IKE")360         CMD_TO_STR.put(CMD_LOCAL_REQUEST_CREATE_IKE, "Create IKE");
CMD_TO_STR.put(CMD_LOCAL_REQUEST_DELETE_IKE, "Delete IKE")361         CMD_TO_STR.put(CMD_LOCAL_REQUEST_DELETE_IKE, "Delete IKE");
CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_IKE, "Rekey IKE")362         CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_IKE, "Rekey IKE");
CMD_TO_STR.put(CMD_LOCAL_REQUEST_INFO, "Info")363         CMD_TO_STR.put(CMD_LOCAL_REQUEST_INFO, "Info");
CMD_TO_STR.put(CMD_LOCAL_REQUEST_DPD, "DPD")364         CMD_TO_STR.put(CMD_LOCAL_REQUEST_DPD, "DPD");
CMD_TO_STR.put(CMD_LOCAL_REQUEST_MOBIKE, "Mobility event")365         CMD_TO_STR.put(CMD_LOCAL_REQUEST_MOBIKE, "Mobility event");
366     }
367 
368     /** Package */
369     @VisibleForTesting final IkeSessionParams mIkeSessionParams;
370 
371     /** Map that stores all IkeSaRecords, keyed by locally generated IKE SPI. */
372     private final LongSparseArray<IkeSaRecord> mLocalSpiToIkeSaRecordMap;
373     /**
374      * Map that stores all ChildSessionStateMachines, keyed by remotely generated Child SPI for
375      * sending IPsec packet. Different SPIs may point to the same ChildSessionStateMachine if this
376      * Child Session is doing Rekey.
377      */
378     private final SparseArray<ChildSessionStateMachine> mRemoteSpiToChildSessionMap;
379 
380     @VisibleForTesting final IkeContext mIkeContext;
381 
382     private final int mIkeSessionId;
383     private final IpSecManager mIpSecManager;
384     private final AlarmManager mAlarmManager;
385     private final IkeLocalRequestScheduler mScheduler;
386     private final IkeSessionCallback mIkeSessionCallback;
387     private final TempFailureHandler mTempFailHandler;
388     private final Dependencies mDeps;
389     private final IkeConnectionController mIkeConnectionCtrl;
390     private final LocalRequestFactory mLocalRequestFactory;
391 
392     /**
393      * mIkeSpiGenerator will be used by all IKE SA creations in this IKE Session to avoid SPI
394      * collision in test mode.
395      */
396     private final IkeSpiGenerator mIkeSpiGenerator;
397     /**
398      * mIpSecSpiGenerator will be shared by all Child Sessions under this IKE Session to avoid SPI
399      * collision in test mode.
400      */
401     private final IpSecSpiGenerator mIpSecSpiGenerator;
402 
403     /** Ensures that the system does not go to sleep in the middle of an exchange. */
404     private final PowerManager.WakeLock mBusyWakeLock;
405 
406     @VisibleForTesting
407     @GuardedBy("mChildCbToSessions")
408     final HashMap<ChildSessionCallback, ChildSessionStateMachine> mChildCbToSessions =
409             new HashMap<>();
410 
411     /** Package private IkeSaProposal that represents the negotiated IKE SA proposal. */
412     @VisibleForTesting IkeSaProposal mSaProposal;
413 
414     @VisibleForTesting IkeCipher mIkeCipher;
415     @VisibleForTesting IkeMacIntegrity mIkeIntegrity;
416     @VisibleForTesting IkeMacPrf mIkePrf;
417 
418     @VisibleForTesting List<byte[]> mRemoteVendorIds = new ArrayList<>();
419     @VisibleForTesting List<Integer> mEnabledExtensions = new ArrayList<>();
420 
421     /** Package */
422     @VisibleForTesting IkeSaRecord mCurrentIkeSaRecord;
423     /** Package */
424     @VisibleForTesting IkeSaRecord mLocalInitNewIkeSaRecord;
425     /** Package */
426     @VisibleForTesting IkeSaRecord mRemoteInitNewIkeSaRecord;
427 
428     /** Package */
429     @VisibleForTesting IkeSaRecord mIkeSaRecordSurviving;
430     /** Package */
431     @VisibleForTesting IkeSaRecord mIkeSaRecordAwaitingLocalDel;
432     /** Package */
433     @VisibleForTesting IkeSaRecord mIkeSaRecordAwaitingRemoteDel;
434 
435     private final Ike3gppExtensionExchange mIke3gppExtensionExchange;
436 
437     // States
438     @VisibleForTesting
439     final KillIkeSessionParent mKillIkeSessionParent = new KillIkeSessionParent();
440     @VisibleForTesting
441     final Initial mInitial = new Initial();
442     @VisibleForTesting
443     final Idle mIdle = new Idle();
444     @VisibleForTesting
445     final ChildProcedureOngoing mChildProcedureOngoing = new ChildProcedureOngoing();
446     @VisibleForTesting
447     final Receiving mReceiving = new Receiving();
448     @VisibleForTesting
449     final CreateIkeLocalIkeInit mCreateIkeLocalIkeInit = new CreateIkeLocalIkeInit();
450 
451     @VisibleForTesting
452     final CreateIkeLocalIkeAuth mCreateIkeLocalIkeAuth = new CreateIkeLocalIkeAuth();
453     @VisibleForTesting
454     final CreateIkeLocalIkeAuthInEap mCreateIkeLocalIkeAuthInEap = new CreateIkeLocalIkeAuthInEap();
455     @VisibleForTesting
456     final CreateIkeLocalIkeAuthPostEap mCreateIkeLocalIkeAuthPostEap =
457             new CreateIkeLocalIkeAuthPostEap();
458 
459     @VisibleForTesting
460     final RekeyIkeLocalCreate mRekeyIkeLocalCreate = new RekeyIkeLocalCreate();
461     @VisibleForTesting
462     final SimulRekeyIkeLocalCreate mSimulRekeyIkeLocalCreate = new SimulRekeyIkeLocalCreate();
463     @VisibleForTesting
464     final SimulRekeyIkeLocalDeleteRemoteDelete mSimulRekeyIkeLocalDeleteRemoteDelete =
465             new SimulRekeyIkeLocalDeleteRemoteDelete();
466     @VisibleForTesting
467     final SimulRekeyIkeLocalDelete mSimulRekeyIkeLocalDelete = new SimulRekeyIkeLocalDelete();
468     @VisibleForTesting
469     final SimulRekeyIkeRemoteDelete mSimulRekeyIkeRemoteDelete = new SimulRekeyIkeRemoteDelete();
470     @VisibleForTesting
471     final RekeyIkeLocalDelete mRekeyIkeLocalDelete = new RekeyIkeLocalDelete();
472     @VisibleForTesting
473     final RekeyIkeRemoteDelete mRekeyIkeRemoteDelete = new RekeyIkeRemoteDelete();
474 
475     @VisibleForTesting
476     final DeleteIkeLocalDelete mDeleteIkeLocalDelete = new DeleteIkeLocalDelete();
477     @VisibleForTesting
478     final DpdIkeLocalInfo mDpdIkeLocalInfo = new DpdIkeLocalInfo();
479     @VisibleForTesting
480     final MobikeLocalInfo mMobikeLocalInfo = new MobikeLocalInfo();
481 
482     /** Constructor for testing. */
483     @VisibleForTesting
IkeSessionStateMachine( Looper looper, Context context, IpSecManager ipSecManager, ConnectivityManager connectMgr, IkeSessionParams ikeParams, ChildSessionParams firstChildParams, Executor userCbExecutor, IkeSessionCallback ikeSessionCallback, ChildSessionCallback firstChildSessionCallback, Dependencies deps)484     public IkeSessionStateMachine(
485             Looper looper,
486             Context context,
487             IpSecManager ipSecManager,
488             ConnectivityManager connectMgr,
489             IkeSessionParams ikeParams,
490             ChildSessionParams firstChildParams,
491             Executor userCbExecutor,
492             IkeSessionCallback ikeSessionCallback,
493             ChildSessionCallback firstChildSessionCallback,
494             Dependencies deps) {
495         super(TAG, looper, userCbExecutor);
496 
497         if (ikeParams.hasIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
498                 || ikeParams.hasIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY)) {
499             if (firstChildParams instanceof TransportModeChildSessionParams) {
500                 throw new IllegalArgumentException(
501                         "Transport Mode SAs not supported when MOBIKE is enabled");
502             } else if (!SdkLevel.isAtLeastS()) {
503                 throw new IllegalStateException("MOBIKE only supported for S+");
504             }
505         }
506 
507         // TODO: Statically store the ikeSessionCallback to prevent user from providing the
508         // same callback instance in the future
509 
510         PowerManager pm = context.getSystemService(PowerManager.class);
511         mBusyWakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, TAG + BUSY_WAKE_LOCK_TAG);
512         mBusyWakeLock.setReferenceCounted(false);
513 
514         mIkeSessionId = sIkeSessionIdGenerator.getAndIncrement();
515 
516         mIkeSessionParams = ikeParams;
517 
518         mTempFailHandler = new TempFailureHandler(looper);
519 
520         // There are at most three IkeSaRecords co-existing during simultaneous rekeying.
521         mLocalSpiToIkeSaRecordMap = new LongSparseArray<>(3);
522         mRemoteSpiToChildSessionMap = new SparseArray<>();
523 
524         mIpSecManager = ipSecManager;
525         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
526 
527         mDeps = deps;
528         mIkeContext =
529                 mDeps.newIkeContext(looper, context, mIkeSessionParams.getConfiguredNetwork());
530         mLocalRequestFactory = mDeps.newLocalRequestFactory();
531         mIkeConnectionCtrl =
532                 mDeps.newIkeConnectionController(
533                         mIkeContext,
534                         new IkeConnectionController.Config(
535                                 mIkeSessionParams,
536                                 mIkeSessionId,
537                                 CMD_ALARM_FIRED,
538                                 CMD_SEND_KEEPALIVE,
539                                 this));
540         mIkeSpiGenerator = new IkeSpiGenerator(mIkeContext.getRandomnessFactory());
541         mIpSecSpiGenerator =
542                 new IpSecSpiGenerator(mIpSecManager, mIkeContext.getRandomnessFactory());
543 
544         mIkeSessionCallback = ikeSessionCallback;
545         registerChildSessionCallback(firstChildParams, firstChildSessionCallback, true);
546 
547         mIke3gppExtensionExchange =
548                 new Ike3gppExtensionExchange(
549                         mIkeSessionParams.getIke3gppExtension(), mUserCbExecutor);
550 
551         // CHECKSTYLE:OFF IndentationCheck
552         addState(mKillIkeSessionParent);
553             addState(mInitial, mKillIkeSessionParent);
554             addState(mCreateIkeLocalIkeInit, mKillIkeSessionParent);
555             addState(mCreateIkeLocalIkeAuth, mKillIkeSessionParent);
556             addState(mCreateIkeLocalIkeAuthInEap, mKillIkeSessionParent);
557             addState(mCreateIkeLocalIkeAuthPostEap, mKillIkeSessionParent);
558             addState(mIdle, mKillIkeSessionParent);
559             addState(mChildProcedureOngoing, mKillIkeSessionParent);
560             addState(mReceiving, mKillIkeSessionParent);
561             addState(mRekeyIkeLocalCreate, mKillIkeSessionParent);
562                 addState(mSimulRekeyIkeLocalCreate, mRekeyIkeLocalCreate);
563             addState(mSimulRekeyIkeLocalDeleteRemoteDelete, mKillIkeSessionParent);
564                 addState(mSimulRekeyIkeLocalDelete, mSimulRekeyIkeLocalDeleteRemoteDelete);
565                 addState(mSimulRekeyIkeRemoteDelete, mSimulRekeyIkeLocalDeleteRemoteDelete);
566             addState(mRekeyIkeLocalDelete, mKillIkeSessionParent);
567             addState(mRekeyIkeRemoteDelete, mKillIkeSessionParent);
568             addState(mDeleteIkeLocalDelete, mKillIkeSessionParent);
569             addState(mDpdIkeLocalInfo, mKillIkeSessionParent);
570             addState(mMobikeLocalInfo, mKillIkeSessionParent);
571         // CHECKSTYLE:ON IndentationCheck
572 
573         // Peer-selected DH group to use. Defaults to first proposed DH group in first SA proposal.
574         int peerSelectedDhGroup =
575                 mIkeSessionParams.getSaProposals().get(0).getDhGroupTransforms()[0].id;
576         mInitial.setIkeSetupData(
577                 new InitialSetupData(
578                         firstChildParams, firstChildSessionCallback, peerSelectedDhGroup));
579         setInitialState(mInitial);
580 
581         // TODO: Find a way to make it safe to release WakeLock when #onNewProcedureReady is called
582         mScheduler =
583                 new IkeLocalRequestScheduler(
584                         localReq -> {
585                             sendMessageAtFrontOfQueue(CMD_EXECUTE_LOCAL_REQ, localReq);
586                         },
587                         mIkeContext.getContext());
588 
589         mBusyWakeLock.acquire();
590         start();
591     }
592 
593     /** Construct an instance of IkeSessionStateMachine. */
IkeSessionStateMachine( Looper looper, Context context, IpSecManager ipSecManager, IkeSessionParams ikeParams, ChildSessionParams firstChildParams, Executor userCbExecutor, IkeSessionCallback ikeSessionCallback, ChildSessionCallback firstChildSessionCallback)594     public IkeSessionStateMachine(
595             Looper looper,
596             Context context,
597             IpSecManager ipSecManager,
598             IkeSessionParams ikeParams,
599             ChildSessionParams firstChildParams,
600             Executor userCbExecutor,
601             IkeSessionCallback ikeSessionCallback,
602             ChildSessionCallback firstChildSessionCallback) {
603         this(
604                 looper,
605                 context,
606                 ipSecManager,
607                 context.getSystemService(ConnectivityManager.class),
608                 ikeParams,
609                 firstChildParams,
610                 userCbExecutor,
611                 ikeSessionCallback,
612                 firstChildSessionCallback,
613                 new Dependencies());
614     }
615 
616     /**
617      * InitialSetupData contains original caller configurations that will be used in IKE setup.
618      *
619      * <p>This class will be instantiated in IkeSessionStateMachine constructor, and then passed to
620      * Initial state and eventually CreateIkeLocalIkeInit state
621      */
622     @VisibleForTesting
623     static class InitialSetupData {
624         public final ChildSessionParams firstChildSessionParams;
625         public final ChildSessionCallback firstChildCallback;
626 
627         /** Peer-selected DH group to use. */
628         public final int peerSelectedDhGroup;
629 
InitialSetupData( ChildSessionParams firstChildSessionParams, ChildSessionCallback firstChildCallback, int peerSelectedDhGroup)630         InitialSetupData(
631                 ChildSessionParams firstChildSessionParams,
632                 ChildSessionCallback firstChildCallback,
633                 int peerSelectedDhGroup) {
634             this.firstChildSessionParams = firstChildSessionParams;
635             this.firstChildCallback = firstChildCallback;
636             this.peerSelectedDhGroup = peerSelectedDhGroup;
637         }
638 
InitialSetupData(InitialSetupData initialSetupData)639         InitialSetupData(InitialSetupData initialSetupData) {
640             this(
641                     initialSetupData.firstChildSessionParams,
642                     initialSetupData.firstChildCallback,
643                     initialSetupData.peerSelectedDhGroup);
644         }
645     }
646 
647     /**
648      * IkeInitData contains caller configurations and IKE INIT exchange results that will be used in
649      * IKE AUTH.
650      *
651      * <p>This class will be instantiated in CreateIkeLocalIkeInit state, and then passed to
652      * CreateIkeLocalIkeAuth state for IKE AUTH exchange(s).
653      */
654     @VisibleForTesting
655     static class IkeInitData extends InitialSetupData {
656         public final byte[] ikeInitRequestBytes;
657         public final byte[] ikeInitResponseBytes;
658         public final IkeNoncePayload ikeInitNoncePayload;
659         public final IkeNoncePayload ikeRespNoncePayload;
660 
661         /** Set of peer-supported Signature Hash Algorithms. Optionally set in IKE INIT. */
662         public final Set<Short> peerSignatureHashAlgorithms = new HashSet<>();
663 
IkeInitData( InitialSetupData initialSetupData, byte[] ikeInitRequestBytes, byte[] ikeInitResponseBytes, IkeNoncePayload ikeInitNoncePayload, IkeNoncePayload ikeRespNoncePayload, Set<Short> peerSignatureHashAlgorithms)664         IkeInitData(
665                 InitialSetupData initialSetupData,
666                 byte[] ikeInitRequestBytes,
667                 byte[] ikeInitResponseBytes,
668                 IkeNoncePayload ikeInitNoncePayload,
669                 IkeNoncePayload ikeRespNoncePayload,
670                 Set<Short> peerSignatureHashAlgorithms) {
671             super(initialSetupData);
672             this.ikeInitRequestBytes = ikeInitRequestBytes;
673             this.ikeInitResponseBytes = ikeInitResponseBytes;
674             this.ikeInitNoncePayload = ikeInitNoncePayload;
675             this.ikeRespNoncePayload = ikeRespNoncePayload;
676 
677             this.peerSignatureHashAlgorithms.addAll(peerSignatureHashAlgorithms);
678         }
679 
IkeInitData(IkeInitData ikeInitData)680         IkeInitData(IkeInitData ikeInitData) {
681             this(
682                     new InitialSetupData(
683                             ikeInitData.firstChildSessionParams,
684                             ikeInitData.firstChildCallback,
685                             ikeInitData.peerSelectedDhGroup),
686                     ikeInitData.ikeInitRequestBytes,
687                     ikeInitData.ikeInitResponseBytes,
688                     ikeInitData.ikeInitNoncePayload,
689                     ikeInitData.ikeRespNoncePayload,
690                     ikeInitData.peerSignatureHashAlgorithms);
691         }
692     }
693 
694     /**
695      * IkeAuthData contains caller configuration and results of IKE INIT and first IKE AUTH exchange
696      * that will be used in the remaining IKE AUTH exchanges.
697      *
698      * <p>This class will be instantiated in CreateIkeLocalIkeAuth state, ane then passed to the
699      * later IKE AUTH states if the authentication requires multiple IKE exchanges.
700      */
701     @VisibleForTesting
702     static class IkeAuthData extends IkeInitData {
703         public final IkeIdPayload initIdPayload;
704         public final IkeIdPayload respIdPayload;
705         public final List<IkePayload> firstChildReqList;
706 
IkeAuthData( IkeInitData ikeInitData, IkeIdPayload initIdPayload, IkeIdPayload respIdPayload, List<IkePayload> firstChildReqList)707         IkeAuthData(
708                 IkeInitData ikeInitData,
709                 IkeIdPayload initIdPayload,
710                 IkeIdPayload respIdPayload,
711                 List<IkePayload> firstChildReqList) {
712             super(ikeInitData);
713             this.initIdPayload = initIdPayload;
714             this.respIdPayload = respIdPayload;
715             this.firstChildReqList = new ArrayList<IkePayload>();
716             this.firstChildReqList.addAll(firstChildReqList);
717         }
718     }
719 
720     /** External dependencies, for injection in tests */
721     @VisibleForTesting
722     public static class Dependencies {
723         /** Builds and returns a new IkeContext */
newIkeContext(Looper looper, Context context, Network network)724         public IkeContext newIkeContext(Looper looper, Context context, Network network) {
725             return new IkeContext(looper, context, new RandomnessFactory(context, network));
726         }
727 
728         /**
729          * Builds and returns a new EapAuthenticator
730          *
731          * @param ikeContext context of an IKE Session
732          * @param cb IEapCallback for callbacks to the client
733          * @param eapSessionConfig EAP session configuration
734          */
newEapAuthenticator( IkeContext ikeContext, IEapCallback cb, EapSessionConfig eapSessionConfig)735         public EapAuthenticator newEapAuthenticator(
736                 IkeContext ikeContext, IEapCallback cb, EapSessionConfig eapSessionConfig) {
737             return new EapAuthenticator(ikeContext, cb, eapSessionConfig);
738         }
739 
740         /** Builds and starts a new ChildSessionStateMachine */
newChildSessionStateMachine( IkeContext ikeContext, ChildSessionStateMachine.Config childSessionSmConfig, ChildSessionCallback userCallbacks, ChildSessionStateMachine.IChildSessionSmCallback childSmCallback)741         public ChildSessionStateMachine newChildSessionStateMachine(
742                 IkeContext ikeContext,
743                 ChildSessionStateMachine.Config childSessionSmConfig,
744                 ChildSessionCallback userCallbacks,
745                 ChildSessionStateMachine.IChildSessionSmCallback childSmCallback) {
746             ChildSessionStateMachine childSession =
747                     new ChildSessionStateMachine(
748                             ikeContext, childSessionSmConfig, userCallbacks, childSmCallback);
749             childSession.start();
750             return childSession;
751         }
752 
753         /** Builds and returns a new IkeConnectionController */
newIkeConnectionController( IkeContext ikeContext, IkeConnectionController.Config config)754         public IkeConnectionController newIkeConnectionController(
755                 IkeContext ikeContext, IkeConnectionController.Config config) {
756             return new IkeConnectionController(ikeContext, config);
757         }
758 
759         /** Gets a LocalRequestFactory */
newLocalRequestFactory()760         public LocalRequestFactory newLocalRequestFactory() {
761             return new LocalRequestFactory();
762         }
763 
764         /**
765          * Creates an alarm to be delivered precisely at the stated time, even when the system is in
766          * low-power idle (a.k.a. doze) modes.
767          */
newExactAndAllowWhileIdleAlarm(IkeAlarmConfig alarmConfig)768         public IkeAlarm newExactAndAllowWhileIdleAlarm(IkeAlarmConfig alarmConfig) {
769             return IkeAlarm.newExactAndAllowWhileIdleAlarm(alarmConfig);
770         }
771     }
772 
hasChildSessionCallback(ChildSessionCallback callback)773     private boolean hasChildSessionCallback(ChildSessionCallback callback) {
774         synchronized (mChildCbToSessions) {
775             return mChildCbToSessions.containsKey(callback);
776         }
777     }
778 
779     /**
780      * Synchronously builds and registers a child session.
781      *
782      * <p>Setup of the child state machines MUST be done in two stages to ensure that if an external
783      * caller calls openChildSession and then calls closeChildSession before the state machine has
784      * gotten a chance to negotiate the sessions, a valid callback mapping exists (and does not
785      * throw an exception that the callback was not found).
786      *
787      * <p>In the edge case where a child creation fails, and deletes itself, all pending requests
788      * will no longer find the session in the map. Assume it has errored/failed, and skip/ignore.
789      * This is safe, as closeChildSession() (previously) validated that the callback was registered.
790      */
791     @VisibleForTesting
registerChildSessionCallback( ChildSessionParams childParams, ChildSessionCallback callbacks, boolean isFirstChild)792     void registerChildSessionCallback(
793             ChildSessionParams childParams, ChildSessionCallback callbacks, boolean isFirstChild) {
794         synchronized (mChildCbToSessions) {
795             if (!isFirstChild && getCurrentState() == null) {
796                 throw new IllegalStateException(
797                         "Request rejected because IKE Session is being closed. ");
798             }
799 
800             mChildCbToSessions.put(
801                     callbacks,
802                     mDeps.newChildSessionStateMachine(
803                             mIkeContext,
804                             new ChildSessionStateMachine.Config(
805                                     mIkeSessionId,
806                                     getHandler(),
807                                     childParams,
808                                     (IpSecManager)
809                                             mIkeContext
810                                                     .getContext()
811                                                     .getSystemService(Context.IPSEC_SERVICE),
812                                     mIpSecSpiGenerator,
813                                     mUserCbExecutor),
814                             callbacks,
815                             new ChildSessionSmCallback()));
816         }
817     }
818 
819     /** Initiates IKE setup procedure. */
openSession()820     public void openSession() {
821         sendMessage(
822                 CMD_LOCAL_REQUEST_CREATE_IKE,
823                 mLocalRequestFactory.getIkeLocalRequest(CMD_LOCAL_REQUEST_CREATE_IKE));
824     }
825 
826     /** Schedules a Create Child procedure. */
openChildSession( ChildSessionParams childSessionParams, ChildSessionCallback childSessionCallback)827     public void openChildSession(
828             ChildSessionParams childSessionParams, ChildSessionCallback childSessionCallback) {
829         if (childSessionCallback == null) {
830             throw new IllegalArgumentException("Child Session Callback must be provided");
831         }
832 
833         if (hasChildSessionCallback(childSessionCallback)) {
834             throw new IllegalArgumentException("Child Session Callback handle already registered");
835         }
836 
837         if (mIkeSessionParams.hasIkeOption(IKE_OPTION_MOBIKE)
838                 && childSessionParams instanceof TransportModeChildSessionParams) {
839             throw new IllegalArgumentException(
840                     "Transport Mode SAs not supported when MOBIKE is enabled");
841         }
842 
843         registerChildSessionCallback(
844                 childSessionParams, childSessionCallback, false /*isFirstChild*/);
845         sendMessage(
846                 CMD_LOCAL_REQUEST_CREATE_CHILD,
847                 mLocalRequestFactory.getChildLocalRequest(
848                         CMD_LOCAL_REQUEST_CREATE_CHILD, childSessionCallback, childSessionParams));
849     }
850 
851     /** Schedules a Delete Child procedure. */
closeChildSession(ChildSessionCallback childSessionCallback)852     public void closeChildSession(ChildSessionCallback childSessionCallback) {
853         if (childSessionCallback == null) {
854             throw new IllegalArgumentException("Child Session Callback must be provided");
855         }
856 
857         if (!hasChildSessionCallback(childSessionCallback)) {
858             throw new IllegalArgumentException("Child Session Callback handle not registered");
859         }
860 
861         sendMessage(
862                 CMD_LOCAL_REQUEST_DELETE_CHILD,
863                 mLocalRequestFactory.getChildLocalRequest(
864                         CMD_LOCAL_REQUEST_DELETE_CHILD, childSessionCallback, null));
865     }
866 
867     /** Initiates Delete IKE procedure. */
closeSession()868     public void closeSession() {
869         sendMessage(
870                 CMD_LOCAL_REQUEST_DELETE_IKE,
871                 mLocalRequestFactory.getIkeLocalRequest(CMD_LOCAL_REQUEST_DELETE_IKE));
872     }
873 
874     /** Update the IkeSessionStateMachine to use the specified Network. */
setNetwork( Network network, @IkeSessionParams.EspIpVersion int ipVersion, @IkeSessionParams.EspEncapType int encapType, int keepaliveDelaySeconds)875     public void setNetwork(
876             Network network,
877             @IkeSessionParams.EspIpVersion int ipVersion,
878             @IkeSessionParams.EspEncapType int encapType,
879             int keepaliveDelaySeconds) {
880         if (network == null) {
881             throw new IllegalArgumentException("network must not be null");
882         }
883 
884         if (ipVersion != ESP_IP_VERSION_AUTO
885                 && ipVersion != ESP_IP_VERSION_IPV4
886                 && ipVersion != ESP_IP_VERSION_IPV6) {
887             throw new IllegalArgumentException("Invalid IP version: " + ipVersion);
888         }
889 
890         if (encapType != ESP_ENCAP_TYPE_AUTO
891                 && encapType != ESP_ENCAP_TYPE_NONE
892                 && encapType != ESP_ENCAP_TYPE_UDP) {
893             throw new IllegalArgumentException("Invalid encap type: " + encapType);
894         }
895 
896         if (keepaliveDelaySeconds != NATT_KEEPALIVE_INTERVAL_AUTO
897                 && (keepaliveDelaySeconds < IKE_NATT_KEEPALIVE_DELAY_SEC_MIN
898                 || keepaliveDelaySeconds > IKE_NATT_KEEPALIVE_DELAY_SEC_MAX)) {
899             throw new IllegalArgumentException("Invalid NATT keepalive delay value");
900         }
901 
902         if (!mIkeSessionParams.hasIkeOption(IKE_OPTION_MOBIKE)
903                 && !mIkeSessionParams.hasIkeOption(IKE_OPTION_REKEY_MOBILITY)) {
904             throw new IllegalStateException(
905                     "This IKE Session is not able to handle network or address changes");
906         }
907 
908         if (mIkeSessionParams.getConfiguredNetwork() == null) {
909             throw new IllegalStateException(
910                     "setNetwork() requires this IkeSession to be configured to use caller-specified"
911                             + " network instead of default network");
912         }
913 
914         sendMessage(CMD_SET_NETWORK,
915                 new NetworkParams(network, ipVersion, encapType, keepaliveDelaySeconds));
916     }
917 
918     /**
919      * Update the IkeSessionMachine to know that it underpins the specified Network.
920      *
921      * In particular, this is used to tell the system to stop keepalives when there are no
922      * open connections on the underpinned network, if automatic on/off keepalives are turned on.
923      */
setUnderpinnedNetwork(@onNull Network underpinnedNetwork)924     public void setUnderpinnedNetwork(@NonNull Network underpinnedNetwork) {
925         Objects.requireNonNull(underpinnedNetwork);
926         sendMessage(CMD_SET_UNDERPINNED_NETWORK, underpinnedNetwork);
927     }
928 
scheduleRetry(LocalRequest localRequest)929     private void scheduleRetry(LocalRequest localRequest) {
930         sendMessageDelayed(localRequest.procedureType, localRequest, RETRY_INTERVAL_MS);
931     }
932 
needEnableForceUdpEncap()933     private boolean needEnableForceUdpEncap() {
934         // When IKE library uses IPv4 and needs to do NAT detection, it needs to enforce UDP
935         // encapsulation to prevent the server from sending non-UDP-encap packets.
936         //
937         // NOTE: Although the IKE spec requires implementations to handle both UDP-encap and
938         // non-UDP-encap ESP packets when both the IKE client and server support NAT-T, due to
939         // kernel restrictions, the Android IPsec stack is unable to allow receiving two types of
940         // packets with a single SA. As a result, before kernel issues (b/210164853) are resolved,
941         // the IKE library MUST enforce UDP Encap to ensure that the server only sends UDP-encap
942         // packets in order to avoid dropping packets.
943         return (mIkeConnectionCtrl.getRemoteAddress() instanceof Inet4Address);
944     }
945 
946     private static class NetworkParams {
947         public final Network network;
948         public final int ipVersion;
949         public final int encapType;
950         public final int keepaliveDelaySeconds;
NetworkParams(Network network, int ipVersion, int encapType, int keepaliveDelaySeconds)951         NetworkParams(Network network, int ipVersion, int encapType,
952                 int keepaliveDelaySeconds) {
953             this.network = network;
954             this.ipVersion = ipVersion;
955             this.encapType = encapType;
956             this.keepaliveDelaySeconds = keepaliveDelaySeconds;
957         }
958     }
959 
960     // TODO: Support initiating Delete IKE exchange when IKE SA expires
961 
962     // TODO: Add interfaces to initiate IKE exchanges.
963 
964     /**
965      * This class is for handling temporary failure.
966      *
967      * <p>Receiving a TEMPORARY_FAILURE is caused by a temporary condition. IKE Session should be
968      * closed if it continues to receive this error after several minutes.
969      */
970     @VisibleForTesting
971     class TempFailureHandler extends Handler {
972         private static final int TEMP_FAILURE_RETRY_TIMEOUT = 1;
973 
974         private boolean mTempFailureReceived = false;
975 
TempFailureHandler(Looper looper)976         TempFailureHandler(Looper looper) {
977             super(looper);
978         }
979 
980         @Override
handleMessage(Message msg)981         public void handleMessage(Message msg) {
982             if (msg.what == TEMP_FAILURE_RETRY_TIMEOUT) {
983                 IOException error =
984                         new IOException(
985                                 "Kept receiving TEMPORARY_FAILURE error. State information is out"
986                                         + " of sync.");
987                 executeUserCallback(
988                         () -> {
989                             mIkeSessionCallback.onClosedWithException(wrapAsIkeException(error));
990                         });
991                 loge("Fatal error", error);
992 
993                 closeAllSaRecords(false /*expectSaClosed*/);
994                 quitSessionNow();
995             } else {
996                 logWtf("Unknown message.what: " + msg.what);
997             }
998         }
999 
1000         /**
1001          * Schedule temporary failure timeout.
1002          *
1003          * <p>Caller of this method is responsible for scheduling retry of the rejected request.
1004          */
handleTempFailure()1005         public void handleTempFailure() {
1006             logd("TempFailureHandler: Receive TEMPORARY FAILURE");
1007 
1008             if (!mTempFailureReceived) {
1009                 sendEmptyMessageDelayed(TEMP_FAILURE_RETRY_TIMEOUT, TEMP_FAILURE_RETRY_TIMEOUT_MS);
1010                 mTempFailureReceived = true;
1011             }
1012         }
1013 
1014         /** Stop tracking temporary condition when request was not rejected by TEMPORARY_FAILURE. */
reset()1015         public void reset() {
1016             logd("TempFailureHandler: Reset Temporary failure retry timeout");
1017             removeMessages(TEMP_FAILURE_RETRY_TIMEOUT);
1018             mTempFailureReceived = false;
1019         }
1020     }
1021 
1022     // TODO: Add methods for building and validating general Informational packet.
1023 
1024     @VisibleForTesting
addIkeSaRecord(IkeSaRecord record)1025     void addIkeSaRecord(IkeSaRecord record) {
1026         mLocalSpiToIkeSaRecordMap.put(record.getLocalSpi(), record);
1027 
1028         // In IKE_INIT exchange, local SPI was registered with this IkeSessionStateMachine before
1029         // IkeSaRecord is created. Calling this method at the end of exchange will double-register
1030         // the SPI but it is safe because the key and value are not changed.
1031         mIkeConnectionCtrl.registerIkeSaRecord(record);
1032     }
1033 
1034     @VisibleForTesting
removeIkeSaRecord(IkeSaRecord record)1035     void removeIkeSaRecord(IkeSaRecord record) {
1036         mIkeConnectionCtrl.unregisterIkeSaRecord(record);
1037         mLocalSpiToIkeSaRecordMap.remove(record.getLocalSpi());
1038     }
1039 
1040     /**
1041      * ReceivedIkePacket is a package private data container consists of decoded IkeHeader and
1042      * encoded IKE packet in a byte array.
1043      */
1044     static class ReceivedIkePacket {
1045         /** Decoded IKE header */
1046         public final IkeHeader ikeHeader;
1047         /** Entire encoded IKE message including IKE header */
1048         public final byte[] ikePacketBytes;
1049 
ReceivedIkePacket(IkeHeader ikeHeader, byte[] ikePacketBytes)1050         ReceivedIkePacket(IkeHeader ikeHeader, byte[] ikePacketBytes) {
1051             this.ikeHeader = ikeHeader;
1052             this.ikePacketBytes = ikePacketBytes;
1053         }
1054     }
1055 
1056     /** Class to group parameters for negotiating the first Child SA. */
1057     private static class FirstChildNegotiationData {
1058         public final ChildSessionParams childSessionParams;
1059         public final ChildSessionCallback childSessionCallback;
1060         public final List<IkePayload> reqPayloads;
1061         public final List<IkePayload> respPayloads;
1062 
FirstChildNegotiationData( ChildSessionParams childSessionParams, ChildSessionCallback childSessionCallback, List<IkePayload> reqPayloads, List<IkePayload> respPayloads)1063         FirstChildNegotiationData(
1064                 ChildSessionParams childSessionParams,
1065                 ChildSessionCallback childSessionCallback,
1066                 List<IkePayload> reqPayloads,
1067                 List<IkePayload> respPayloads) {
1068             this.childSessionParams = childSessionParams;
1069             this.childSessionCallback = childSessionCallback;
1070             this.reqPayloads = reqPayloads;
1071             this.respPayloads = respPayloads;
1072         }
1073     }
1074 
1075     /** Class to group parameters for notifying the IKE fatal error. */
1076     private static class IkeFatalErrorFromChild {
1077         public final Exception exception;
1078 
IkeFatalErrorFromChild(Exception exception)1079         IkeFatalErrorFromChild(Exception exception) {
1080             this.exception = exception;
1081         }
1082     }
1083 
1084     /** Class to group parameters for building an outbound message for ChildSessions. */
1085     private static class ChildOutboundData {
1086         @ExchangeType public final int exchangeType;
1087         public final boolean isResp;
1088         public final List<IkePayload> payloadList;
1089         public final ChildSessionStateMachine childSession;
1090 
ChildOutboundData( @xchangeType int exchangeType, boolean isResp, List<IkePayload> payloadList, ChildSessionStateMachine childSession)1091         ChildOutboundData(
1092                 @ExchangeType int exchangeType,
1093                 boolean isResp,
1094                 List<IkePayload> payloadList,
1095                 ChildSessionStateMachine childSession) {
1096             this.exchangeType = exchangeType;
1097             this.isResp = isResp;
1098             this.payloadList = payloadList;
1099             this.childSession = childSession;
1100         }
1101     }
1102 
1103     /** Callback for ChildSessionStateMachine to notify IkeSessionStateMachine. */
1104     @VisibleForTesting
1105     class ChildSessionSmCallback implements ChildSessionStateMachine.IChildSessionSmCallback {
1106         @Override
onChildSaCreated(int remoteSpi, ChildSessionStateMachine childSession)1107         public void onChildSaCreated(int remoteSpi, ChildSessionStateMachine childSession) {
1108             mRemoteSpiToChildSessionMap.put(remoteSpi, childSession);
1109         }
1110 
1111         @Override
onChildSaDeleted(int remoteSpi)1112         public void onChildSaDeleted(int remoteSpi) {
1113             mRemoteSpiToChildSessionMap.remove(remoteSpi);
1114         }
1115 
1116         @Override
scheduleRetryLocalRequest(ChildLocalRequest childRequest)1117         public void scheduleRetryLocalRequest(ChildLocalRequest childRequest) {
1118             scheduleRetry(childRequest);
1119         }
1120 
1121         @Override
onOutboundPayloadsReady( @xchangeType int exchangeType, boolean isResp, List<IkePayload> payloadList, ChildSessionStateMachine childSession)1122         public void onOutboundPayloadsReady(
1123                 @ExchangeType int exchangeType,
1124                 boolean isResp,
1125                 List<IkePayload> payloadList,
1126                 ChildSessionStateMachine childSession) {
1127             sendMessage(
1128                     CMD_OUTBOUND_CHILD_PAYLOADS_READY,
1129                     new ChildOutboundData(exchangeType, isResp, payloadList, childSession));
1130         }
1131 
1132         @Override
onProcedureFinished(ChildSessionStateMachine childSession)1133         public void onProcedureFinished(ChildSessionStateMachine childSession) {
1134             if (getHandler() == null) {
1135                 // If the state machine has quit (because IKE Session is being closed), do not send
1136                 // any message.
1137                 return;
1138             }
1139 
1140             sendMessage(CMD_CHILD_PROCEDURE_FINISHED, childSession);
1141         }
1142 
1143         @Override
onChildSessionClosed(ChildSessionCallback userCallbacks)1144         public void onChildSessionClosed(ChildSessionCallback userCallbacks) {
1145             synchronized (mChildCbToSessions) {
1146                 mChildCbToSessions.remove(userCallbacks);
1147             }
1148         }
1149 
1150         @Override
onFatalIkeSessionError(Exception exception)1151         public void onFatalIkeSessionError(Exception exception) {
1152             sendMessage(CMD_IKE_FATAL_ERROR_FROM_CHILD, new IkeFatalErrorFromChild(exception));
1153         }
1154     }
1155 
1156     /** Top level state for handling uncaught exceptions for all subclasses. */
1157     abstract class ExceptionHandler extends ExceptionHandlerBase {
1158         @Override
cleanUpAndQuit(RuntimeException e)1159         protected void cleanUpAndQuit(RuntimeException e) {
1160             // Clean up all SaRecords.
1161             closeAllSaRecords(false /*expectSaClosed*/);
1162 
1163             executeUserCallback(
1164                     () -> {
1165                         mIkeSessionCallback.onClosedWithException(wrapAsIkeException(e));
1166                     });
1167             logWtf("Unexpected exception in " + getCurrentStateName(), e);
1168             quitSessionNow();
1169         }
1170 
1171         @Override
getCmdString(int cmd)1172         protected String getCmdString(int cmd) {
1173             return CMD_TO_STR.get(cmd);
1174         }
1175     }
1176 
1177     /** Called when this StateMachine quits. */
1178     @Override
onQuitting()1179     protected void onQuitting() {
1180         // Clean up all SaRecords.
1181         closeAllSaRecords(true /*expectSaClosed*/);
1182 
1183         synchronized (mChildCbToSessions) {
1184             for (ChildSessionStateMachine child : mChildCbToSessions.values()) {
1185                 // Fire asynchronous call for Child Sessions to do cleanup and remove itself
1186                 // from the map.
1187                 child.killSession();
1188             }
1189         }
1190 
1191         mIkeConnectionCtrl.tearDown();
1192         releaseAlarmReceiver(mIkeContext.getContext(), this, mIkeSessionId);
1193 
1194         mIke3gppExtensionExchange.close();
1195 
1196         mBusyWakeLock.release();
1197         mScheduler.releaseAllLocalRequestWakeLocks();
1198     }
1199 
closeAllSaRecords(boolean expectSaClosed)1200     private void closeAllSaRecords(boolean expectSaClosed) {
1201         closeIkeSaRecord(mCurrentIkeSaRecord, expectSaClosed);
1202         closeIkeSaRecord(mLocalInitNewIkeSaRecord, expectSaClosed);
1203         closeIkeSaRecord(mRemoteInitNewIkeSaRecord, expectSaClosed);
1204 
1205         mCurrentIkeSaRecord = null;
1206         mLocalInitNewIkeSaRecord = null;
1207         mRemoteInitNewIkeSaRecord = null;
1208     }
1209 
closeIkeSaRecord(IkeSaRecord ikeSaRecord, boolean expectSaClosed)1210     private void closeIkeSaRecord(IkeSaRecord ikeSaRecord, boolean expectSaClosed) {
1211         if (ikeSaRecord == null) return;
1212 
1213         removeIkeSaRecord(ikeSaRecord);
1214         ikeSaRecord.close();
1215 
1216         if (!expectSaClosed) return;
1217 
1218         logWtf(
1219                 "IkeSaRecord with local SPI: "
1220                         + ikeSaRecord.getLocalSpi()
1221                         + " is not correctly closed.");
1222     }
1223 
handleIkeFatalError(Exception error)1224     private void handleIkeFatalError(Exception error) {
1225         IkeException ikeException = wrapAsIkeException(error);
1226         loge("IKE Session fatal error in " + getCurrentState().getName(), ikeException);
1227 
1228         try {
1229             // Clean up all SaRecords.
1230             closeAllSaRecords(false /*expectSaClosed*/);
1231         } catch (Exception e) {
1232             // This try catch block is to add a protection in case there is a program error. The
1233             // error is not actionable to IKE callers.
1234             logWtf("Unexpected error in #handleIkeFatalError", e);
1235         } finally {
1236             executeUserCallback(
1237                     () -> {
1238                         mIkeSessionCallback.onClosedWithException(ikeException);
1239                     });
1240             quitSessionNow();
1241         }
1242     }
1243 
1244     /** Parent state used to delete IKE sessions */
1245     class KillIkeSessionParent extends ExceptionHandler {
1246         @Override
processStateMessage(Message message)1247         public boolean processStateMessage(Message message) {
1248             switch (message.what) {
1249                 case CMD_KILL_SESSION:
1250                     closeAllSaRecords(false /*expectSaClosed*/);
1251                     executeUserCallback(
1252                             () -> {
1253                                 mIkeSessionCallback.onClosed();
1254                             });
1255                     quitSessionNow();
1256                     return HANDLED;
1257                 default:
1258                     return NOT_HANDLED;
1259             }
1260         }
1261     }
1262 
1263     // This method should always run on the IKE worker thread
setupAlarmReceiver( Handler ikeHandler, Context context, IkeSessionStateMachine ike, int ikeSessionId)1264     private static void setupAlarmReceiver(
1265             Handler ikeHandler, Context context, IkeSessionStateMachine ike, int ikeSessionId) {
1266         if (!sContextToIkeSmMap.containsKey(context)) {
1267             int flags = SdkLevel.isAtLeastT() ? Context.RECEIVER_NOT_EXPORTED : 0;
1268             // Pass in a Handler so #onReceive will run on the StateMachine thread
1269             context.registerReceiver(
1270                     sIkeAlarmReceiver,
1271                     sIntentFilter,
1272                     null /* broadcastPermission */,
1273                     ikeHandler,
1274                     flags);
1275             sContextToIkeSmMap.put(context, new HashSet<IkeSessionStateMachine>());
1276         }
1277         sContextToIkeSmMap.get(context).add(ike);
1278 
1279         sIkeAlarmReceiver.registerIkeSession(ikeSessionId, ikeHandler);
1280     }
1281 
1282     // This method should always run on the IKE worker thread
releaseAlarmReceiver( Context context, IkeSessionStateMachine ike, int ikeSessionId)1283     private static void releaseAlarmReceiver(
1284             Context context, IkeSessionStateMachine ike, int ikeSessionId) {
1285         sIkeAlarmReceiver.unregisterIkeSession(ikeSessionId);
1286 
1287         Set<IkeSessionStateMachine> ikeSet = sContextToIkeSmMap.get(context);
1288         ikeSet.remove(ike);
1289         if (ikeSet.isEmpty()) {
1290             context.unregisterReceiver(sIkeAlarmReceiver);
1291             sContextToIkeSmMap.remove(context);
1292         }
1293     }
1294 
1295     /** Initial state of IkeSessionStateMachine. */
1296     class Initial extends ExceptionHandler {
1297         private InitialSetupData mInitialSetupData;
1298 
1299         /** Reset resources that might have been created when this state was entered previously */
reset()1300         private void reset() {
1301             mIkeConnectionCtrl.tearDown();
1302         }
1303 
1304         @Override
enterState()1305         public void enterState() {
1306             if (mInitialSetupData == null) {
1307                 handleIkeFatalError(
1308                         wrapAsIkeException(new IllegalStateException("mInitialSetupData is null")));
1309                 return;
1310             }
1311 
1312             reset();
1313 
1314             setupAlarmReceiver(
1315                     getHandler(),
1316                     mIkeContext.getContext(),
1317                     IkeSessionStateMachine.this,
1318                     mIkeSessionId);
1319             try {
1320                 mIkeConnectionCtrl.setUp();
1321 
1322                 // TODO(b/191673438): Set a specific tag for VPN.
1323                 TrafficStats.setThreadStatsTag(Process.myUid());
1324             } catch (IkeException e) {
1325                 handleIkeFatalError(e);
1326             }
1327         }
1328 
setIkeSetupData(InitialSetupData setupData)1329         public void setIkeSetupData(InitialSetupData setupData) {
1330             mInitialSetupData = setupData;
1331         }
1332 
1333         @Override
processStateMessage(Message message)1334         public boolean processStateMessage(Message message) {
1335             switch (message.what) {
1336                 case CMD_LOCAL_REQUEST_CREATE_IKE:
1337                     mCreateIkeLocalIkeInit.setIkeSetupData(mInitialSetupData);
1338                     transitionTo(mCreateIkeLocalIkeInit);
1339                     return HANDLED;
1340                 case CMD_FORCE_TRANSITION:
1341                     transitionTo((State) message.obj);
1342                     return HANDLED;
1343                 default:
1344                     return NOT_HANDLED;
1345             }
1346         }
1347 
1348         @Override
exitState()1349         public void exitState() {
1350             mInitialSetupData = null;
1351         }
1352     }
1353 
1354     /**
1355      * Idle represents a state when there is no ongoing IKE exchange affecting established IKE SA.
1356      */
1357     class Idle extends LocalRequestQueuer {
1358         private IkeAlarm mDpdAlarm;
1359 
1360         // TODO (b/152236790): Add wakelock for awaiting LocalRequests and ongoing procedures.
1361 
1362         @Override
enterState()1363         public void enterState() {
1364             if (!mScheduler.readyForNextProcedure()) {
1365                 mBusyWakeLock.release();
1366             }
1367 
1368             int dpdDelaySeconds = mIkeSessionParams.getDpdDelaySeconds();
1369             if (dpdDelaySeconds == IkeSessionParams.IKE_DPD_DELAY_SEC_DISABLED) {
1370                 return;
1371             }
1372 
1373             long dpdDelayMs = TimeUnit.SECONDS.toMillis(dpdDelaySeconds);
1374             long remoteIkeSpi = mCurrentIkeSaRecord.getRemoteSpi();
1375             Message intentIkeMsg = getIntentIkeSmMsg(CMD_LOCAL_REQUEST_DPD, remoteIkeSpi);
1376             PendingIntent dpdIntent =
1377                     IkeAlarm.buildIkeAlarmIntent(
1378                             mIkeContext.getContext(),
1379                             ACTION_DPD,
1380                             getIntentIdentifier(mIkeSessionId, remoteIkeSpi),
1381                             intentIkeMsg);
1382 
1383             // Initiating DPD is a way to detect the aliveness of the remote server and also a
1384             // way to assert the aliveness of IKE library. Considering this, the alarm to
1385             // trigger DPD needs to go off even when device is in doze mode to decrease the chance
1386             // the remote server thinks IKE library is dead. Also, since DPD initiation is
1387             // time-critical, we need to use "setExact" to avoid the batching alarm delay which
1388             // can be at most 75% for the alarm timeout (@see AlarmManagerService#maxTriggerTime).
1389             // Please check AlarmManager#setExactAndAllowWhileIdle for more details.
1390             mDpdAlarm =
1391                     mDeps.newExactAndAllowWhileIdleAlarm(
1392                             new IkeAlarmConfig(
1393                                     mIkeContext.getContext(),
1394                                     ACTION_DPD,
1395                                     dpdDelayMs,
1396                                     dpdIntent,
1397                                     intentIkeMsg));
1398             mDpdAlarm.schedule();
1399             logd("DPD Alarm scheduled with DPD delay: " + dpdDelayMs + "ms");
1400         }
1401 
1402         @Override
exitState()1403         protected void exitState() {
1404             // #exitState is guaranteed to be invoked when quit() or quitSessionNow() is called
1405             if (mDpdAlarm != null) {
1406                 mDpdAlarm.cancel();
1407                 logd("DPD Alarm canceled");
1408             }
1409 
1410             mBusyWakeLock.acquire();
1411         }
1412 
1413         @Override
processStateMessage(Message message)1414         public boolean processStateMessage(Message message) {
1415             switch (message.what) {
1416                 case CMD_RECEIVE_IKE_PACKET:
1417                     deferMessage(message);
1418                     transitionTo(mReceiving);
1419                     return HANDLED;
1420 
1421                 case CMD_ALARM_FIRED:
1422                     handleFiredAlarm(message);
1423                     return HANDLED;
1424 
1425                 case CMD_FORCE_TRANSITION: // Testing command
1426                     transitionTo((State) message.obj);
1427                     return HANDLED;
1428 
1429                 case CMD_EXECUTE_LOCAL_REQ:
1430                     executeLocalRequest((LocalRequest) message.obj, message);
1431                     return HANDLED;
1432 
1433                 case CMD_KILL_SESSION:
1434                     // Notify the remote that the IKE Session is being deleted. This notification is
1435                     // sent as a best-effort, so don't worry about retransmitting.
1436                     sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
1437 
1438                     // Let KillIkeSessionParent handle the rest of the cleanup.
1439                     return NOT_HANDLED;
1440 
1441                 case CMD_SET_NETWORK:
1442                     if (!mIkeConnectionCtrl.isMobilityEnabled()) {
1443                         logi("setNetwork() called for session without mobility support.");
1444 
1445                         // TODO(b/224686889): Notify caller of failed mobility attempt.
1446                         return HANDLED;
1447                     }
1448 
1449                     try {
1450                         final NetworkParams params = (NetworkParams) message.obj;
1451                         mIkeConnectionCtrl.onNetworkSetByUser(
1452                                 params.network,
1453                                 params.ipVersion,
1454                                 params.encapType,
1455                                 params.keepaliveDelaySeconds);
1456                     } catch (IkeException e) {
1457                         handleIkeFatalError(e);
1458                     }
1459 
1460                     return HANDLED;
1461 
1462                 case CMD_SET_UNDERPINNED_NETWORK:
1463                     try {
1464                         mIkeConnectionCtrl.onUnderpinnedNetworkSetByUser((Network) message.obj);
1465                     } catch (IkeException e) {
1466                         handleIkeFatalError(e);
1467                     }
1468                     return HANDLED;
1469 
1470                 default:
1471                     // Queue local requests, and trigger next procedure
1472                     if (isLocalRequest(message.what)) {
1473                         handleLocalRequest(message.what, (LocalRequest) message.obj);
1474 
1475                         // Synchronously calls through to the scheduler callback, which will
1476                         // post the CMD_EXECUTE_LOCAL_REQ to the front of the queue, ensuring
1477                         // it is always the next request processed.
1478                         mScheduler.readyForNextProcedure();
1479                         return HANDLED;
1480                     }
1481                     return NOT_HANDLED;
1482             }
1483         }
1484 
executeLocalRequest(LocalRequest req, Message message)1485         private void executeLocalRequest(LocalRequest req, Message message) {
1486             req.releaseWakeLock();
1487 
1488             if (!isRequestForCurrentSa(req)) {
1489                 logd("Request is for a deleted SA. Ignore it.");
1490                 mScheduler.readyForNextProcedure();
1491                 return;
1492             }
1493 
1494             switch (req.procedureType) {
1495                 case CMD_LOCAL_REQUEST_REKEY_IKE:
1496                     transitionTo(mRekeyIkeLocalCreate);
1497                     break;
1498                 case CMD_LOCAL_REQUEST_DELETE_IKE:
1499                     transitionTo(mDeleteIkeLocalDelete);
1500                     break;
1501                 case CMD_LOCAL_REQUEST_DPD:
1502                     transitionTo(mDpdIkeLocalInfo);
1503                     break;
1504                 case CMD_LOCAL_REQUEST_CREATE_CHILD: // fallthrough
1505                 case CMD_LOCAL_REQUEST_REKEY_CHILD: // fallthrough
1506                 case CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE: // fallthrough
1507                 case CMD_LOCAL_REQUEST_MIGRATE_CHILD: // fallthrough
1508                 case CMD_LOCAL_REQUEST_DELETE_CHILD:
1509                     deferMessage(message);
1510                     transitionTo(mChildProcedureOngoing);
1511                     break;
1512                 case CMD_LOCAL_REQUEST_MOBIKE:
1513                     transitionTo(mMobikeLocalInfo);
1514                     break;
1515                 default:
1516                     cleanUpAndQuit(
1517                             new IllegalStateException(
1518                                     "Invalid local request procedure type: " + req.procedureType));
1519             }
1520         }
1521 
1522         // When in Idle state, this IkeSessionStateMachine and all its ChildSessionStateMachines
1523         // only have one alive IKE/Child SA respectively. Returns true if this local request is for
1524         // the current IKE/Child SA, or false if the request is for a deleted SA.
isRequestForCurrentSa(LocalRequest localRequest)1525         private boolean isRequestForCurrentSa(LocalRequest localRequest) {
1526             if (localRequest.isChildRequest()) {
1527                 ChildLocalRequest req = (ChildLocalRequest) localRequest;
1528                 if (req.remoteSpi == IkeLocalRequestScheduler.SPI_NOT_INCLUDED
1529                         || mRemoteSpiToChildSessionMap.get(req.remoteSpi) != null) {
1530                     return true;
1531                 }
1532             } else {
1533                 IkeLocalRequest req = (IkeLocalRequest) localRequest;
1534                 if (req.remoteSpi == IkeLocalRequestScheduler.SPI_NOT_INCLUDED
1535                         || req.remoteSpi == mCurrentIkeSaRecord.getRemoteSpi()) {
1536                     return true;
1537                 }
1538             }
1539             return false;
1540         }
1541     }
1542 
getIntentIdentifier(int ikeSessionId, long remoteIkeSpi)1543     private static String getIntentIdentifier(int ikeSessionId, long remoteIkeSpi) {
1544         return TAG + "_" + ikeSessionId + "_" + remoteIkeSpi;
1545     }
1546 
getIntentIkeSmMsg(int localRequestType, long remoteIkeSpi)1547     private Message getIntentIkeSmMsg(int localRequestType, long remoteIkeSpi) {
1548         Bundle spiBundle = new Bundle();
1549         spiBundle.putLong(BUNDLE_KEY_IKE_REMOTE_SPI, remoteIkeSpi);
1550 
1551         return obtainMessage(CMD_ALARM_FIRED, mIkeSessionId, localRequestType, spiBundle);
1552     }
1553 
1554     @VisibleForTesting
buildSaLifetimeAlarmScheduler(long remoteSpi)1555     SaLifetimeAlarmScheduler buildSaLifetimeAlarmScheduler(long remoteSpi) {
1556         Message deleteMsg = getIntentIkeSmMsg(CMD_LOCAL_REQUEST_DELETE_IKE, remoteSpi);
1557         Message rekeyMsg = getIntentIkeSmMsg(CMD_LOCAL_REQUEST_REKEY_IKE, remoteSpi);
1558 
1559         PendingIntent deleteSaIntent =
1560                 IkeAlarm.buildIkeAlarmIntent(
1561                         mIkeContext.getContext(),
1562                         ACTION_DELETE_IKE,
1563                         getIntentIdentifier(mIkeSessionId, remoteSpi),
1564                         deleteMsg);
1565         PendingIntent rekeySaIntent =
1566                 IkeAlarm.buildIkeAlarmIntent(
1567                         mIkeContext.getContext(),
1568                         ACTION_REKEY_IKE,
1569                         getIntentIdentifier(mIkeSessionId, remoteSpi),
1570                         rekeyMsg);
1571 
1572         return new SaLifetimeAlarmScheduler(
1573                 new IkeAlarmConfig(
1574                         mIkeContext.getContext(),
1575                         ACTION_DELETE_IKE,
1576                         mIkeSessionParams.getHardLifetimeMsInternal(),
1577                         deleteSaIntent,
1578                         deleteMsg),
1579                 new IkeAlarmConfig(
1580                         mIkeContext.getContext(),
1581                         ACTION_REKEY_IKE,
1582                         mIkeSessionParams.getSoftLifetimeMsInternal(),
1583                         rekeySaIntent,
1584                         rekeyMsg));
1585     }
1586 
1587     // Sends the provided IkeMessage using the current IKE SA record
1588     @VisibleForTesting
sendEncryptedIkeMessage(IkeMessage msg)1589     void sendEncryptedIkeMessage(IkeMessage msg) {
1590         sendEncryptedIkeMessage(mCurrentIkeSaRecord, msg);
1591     }
1592 
1593     // Sends the provided IkeMessage using the provided IKE SA record
1594     @VisibleForTesting
sendEncryptedIkeMessage(IkeSaRecord ikeSaRecord, IkeMessage msg)1595     void sendEncryptedIkeMessage(IkeSaRecord ikeSaRecord, IkeMessage msg) {
1596         byte[][] packetList =
1597                 msg.encryptAndEncode(
1598                         mIkeIntegrity,
1599                         mIkeCipher,
1600                         ikeSaRecord,
1601                         mEnabledExtensions.contains(EXTENSION_TYPE_FRAGMENTATION),
1602                         DEFAULT_FRAGMENT_SIZE);
1603         sendEncryptedIkePackets(packetList);
1604 
1605         if (msg.ikeHeader.isResponseMsg) {
1606             ikeSaRecord.updateLastSentRespAllPackets(
1607                     Arrays.asList(packetList), msg.ikeHeader.messageId);
1608         }
1609     }
1610 
sendEncryptedIkePackets(byte[][] packetList)1611     private void sendEncryptedIkePackets(byte[][] packetList) {
1612         for (byte[] packet : packetList) {
1613             mIkeConnectionCtrl.sendIkePacket(packet);
1614         }
1615     }
1616 
1617     // Builds and sends IKE-level error notification response on the provided IKE SA record
1618     @VisibleForTesting
buildAndSendErrorNotificationResponse( IkeSaRecord ikeSaRecord, int messageId, @ErrorType int errorType)1619     void buildAndSendErrorNotificationResponse(
1620             IkeSaRecord ikeSaRecord, int messageId, @ErrorType int errorType) {
1621         IkeNotifyPayload error = new IkeNotifyPayload(errorType);
1622         buildAndSendNotificationResponse(ikeSaRecord, messageId, error);
1623     }
1624 
1625     // Builds and sends error notification response on the provided IKE SA record
1626     @VisibleForTesting
buildAndSendNotificationResponse( IkeSaRecord ikeSaRecord, int messageId, IkeNotifyPayload notifyPayload)1627     void buildAndSendNotificationResponse(
1628             IkeSaRecord ikeSaRecord, int messageId, IkeNotifyPayload notifyPayload) {
1629         IkeMessage msg =
1630                 buildEncryptedNotificationMessage(
1631                         ikeSaRecord,
1632                         new IkeInformationalPayload[] {notifyPayload},
1633                         EXCHANGE_TYPE_INFORMATIONAL,
1634                         true /*isResponse*/,
1635                         messageId);
1636 
1637         sendEncryptedIkeMessage(ikeSaRecord, msg);
1638     }
1639 
1640     // Builds an Encrypted IKE Informational Message for the given IkeInformationalPayload using the
1641     // current IKE SA record.
1642     @VisibleForTesting
buildEncryptedInformationalMessage( IkeInformationalPayload[] payloads, boolean isResponse, int messageId)1643     IkeMessage buildEncryptedInformationalMessage(
1644             IkeInformationalPayload[] payloads, boolean isResponse, int messageId) {
1645         return buildEncryptedInformationalMessage(
1646                 mCurrentIkeSaRecord, payloads, isResponse, messageId);
1647     }
1648 
1649     // Builds an Encrypted IKE Informational Message for the given IkeInformationalPayload using the
1650     // provided IKE SA record.
1651     @VisibleForTesting
buildEncryptedInformationalMessage( IkeSaRecord saRecord, IkeInformationalPayload[] payloads, boolean isResponse, int messageId)1652     IkeMessage buildEncryptedInformationalMessage(
1653             IkeSaRecord saRecord,
1654             IkeInformationalPayload[] payloads,
1655             boolean isResponse,
1656             int messageId) {
1657         return buildEncryptedNotificationMessage(
1658                 saRecord, payloads, IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, isResponse, messageId);
1659     }
1660 
1661     // Builds an Encrypted IKE Message for the given IkeInformationalPayload using the provided IKE
1662     // SA record and exchange type.
1663     @VisibleForTesting
buildEncryptedNotificationMessage( IkeSaRecord saRecord, IkeInformationalPayload[] payloads, @ExchangeType int exchangeType, boolean isResponse, int messageId)1664     IkeMessage buildEncryptedNotificationMessage(
1665             IkeSaRecord saRecord,
1666             IkeInformationalPayload[] payloads,
1667             @ExchangeType int exchangeType,
1668             boolean isResponse,
1669             int messageId) {
1670         IkeHeader header =
1671                 new IkeHeader(
1672                         saRecord.getInitiatorSpi(),
1673                         saRecord.getResponderSpi(),
1674                         IkePayload.PAYLOAD_TYPE_SK,
1675                         exchangeType,
1676                         isResponse /*isResponseMsg*/,
1677                         saRecord.isLocalInit /*fromIkeInitiator*/,
1678                         messageId);
1679 
1680         return new IkeMessage(header, Arrays.asList(payloads));
1681     }
1682 
1683     private abstract class LocalRequestQueuer extends ExceptionHandler {
1684         /**
1685          * Reroutes all local requests to the scheduler
1686          *
1687          * @param requestVal The command value of the request
1688          * @param req The instance of the LocalRequest to be queued.
1689          */
handleLocalRequest(int requestVal, LocalRequest req)1690         protected void handleLocalRequest(int requestVal, LocalRequest req) {
1691             switch (requestVal) {
1692                 case CMD_LOCAL_REQUEST_DELETE_IKE: // Fallthrough
1693                 case CMD_LOCAL_REQUEST_MOBIKE: // Fallthrough
1694                 case CMD_LOCAL_REQUEST_REKEY_IKE: // Fallthrough
1695                 case CMD_LOCAL_REQUEST_INFO: // Fallthrough
1696                 case CMD_LOCAL_REQUEST_DPD:
1697                     mScheduler.addRequest(req);
1698                     return;
1699 
1700                 case CMD_LOCAL_REQUEST_CREATE_CHILD: // Fallthrough
1701                 case CMD_LOCAL_REQUEST_REKEY_CHILD: // Fallthrough
1702                 case CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE: // Fallthrough
1703                 case CMD_LOCAL_REQUEST_MIGRATE_CHILD: // Fallthrough
1704                 case CMD_LOCAL_REQUEST_DELETE_CHILD:
1705                     ChildLocalRequest childReq = (ChildLocalRequest) req;
1706                     if (childReq.procedureType != requestVal) {
1707                         cleanUpAndQuit(
1708                                 new IllegalArgumentException(
1709                                         "ChildLocalRequest procedure type was invalid"));
1710                     }
1711                     mScheduler.addRequest(childReq);
1712                     return;
1713 
1714                 default:
1715                     cleanUpAndQuit(
1716                             new IllegalStateException(
1717                                     "Unknown local request passed to handleLocalRequest"));
1718             }
1719         }
1720 
1721         /** Check if received signal is a local request. */
isLocalRequest(int msgWhat)1722         protected boolean isLocalRequest(int msgWhat) {
1723             if ((msgWhat >= CMD_IKE_LOCAL_REQUEST_BASE
1724                             && msgWhat < CMD_IKE_LOCAL_REQUEST_BASE + CMD_CATEGORY_SIZE)
1725                     || (msgWhat >= CMD_CHILD_LOCAL_REQUEST_BASE
1726                             && msgWhat < CMD_CHILD_LOCAL_REQUEST_BASE + CMD_CATEGORY_SIZE)) {
1727                 return true;
1728             }
1729             return false;
1730         }
1731 
handleFiredAlarm(Message message)1732         protected void handleFiredAlarm(Message message) {
1733             switch (message.arg2) {
1734                 case CMD_SEND_KEEPALIVE:
1735                     mIkeConnectionCtrl.fireKeepAlive();
1736                     return;
1737                 case CMD_LOCAL_REQUEST_DELETE_CHILD: // Hits hard lifetime; fall through
1738                 case CMD_LOCAL_REQUEST_REKEY_CHILD: // Hits soft lifetime
1739                     int remoteChildSpi = ((Bundle) message.obj).getInt(BUNDLE_KEY_CHILD_REMOTE_SPI);
1740                     enqueueLocalRequestSynchronously(
1741                             mLocalRequestFactory.getChildLocalRequest(
1742                                     message.arg2, remoteChildSpi));
1743                     return;
1744                 case CMD_LOCAL_REQUEST_DELETE_IKE: // Hits hard lifetime; fall through
1745                 case CMD_LOCAL_REQUEST_REKEY_IKE: // Hits soft lifetime; fall through
1746                 case CMD_LOCAL_REQUEST_DPD:
1747                     // IKE Session has not received any protectd IKE packet for the whole DPD delay
1748                     long remoteIkeSpi = ((Bundle) message.obj).getLong(BUNDLE_KEY_IKE_REMOTE_SPI);
1749                     enqueueLocalRequestSynchronously(
1750                             mLocalRequestFactory.getIkeLocalRequest(message.arg2, remoteIkeSpi));
1751 
1752                     // TODO(b/152442041): Cancel the scheduled DPD request if IKE Session starts any
1753                     // procedure before DPD get executed.
1754                     return;
1755                 default:
1756                     logWtf("Invalid alarm action: " + message.arg2);
1757             }
1758         }
1759 
enqueueLocalRequestSynchronously(LocalRequest request)1760         private void enqueueLocalRequestSynchronously(LocalRequest request) {
1761             // Use dispatchMessage to synchronously handle this message so that the AlarmManager
1762             // WakeLock can keep protecting this message until it is enquequed in mScheduler. It is
1763             // safe because the alarmReceiver is called on the Ike HandlerThread, and the
1764             // IkeSessionStateMachine is not currently in a state transition.
1765             getHandler().dispatchMessage(obtainMessage(request.procedureType, request));
1766         }
1767 
1768         /** Builds a IKE Delete Request for the given IKE SA. */
buildIkeDeleteReq(IkeSaRecord ikeSaRecord)1769         protected IkeMessage buildIkeDeleteReq(IkeSaRecord ikeSaRecord) {
1770             IkeInformationalPayload[] payloads =
1771                     new IkeInformationalPayload[] {new IkeDeletePayload()};
1772             return buildEncryptedInformationalMessage(
1773                     ikeSaRecord,
1774                     payloads,
1775                     false /* isResp */,
1776                     ikeSaRecord.getLocalRequestMessageId());
1777         }
1778     }
1779 
1780     /**
1781      * Base state defines common behaviours when receiving an IKE packet.
1782      *
1783      * <p>State that represents an ongoing IKE procedure MUST extend BusyState to handle received
1784      * IKE packet. Idle state will defer the received packet to a BusyState to process it.
1785      */
1786     private abstract class BusyState extends LocalRequestQueuer {
1787         @Override
processStateMessage(Message message)1788         public boolean processStateMessage(Message message) {
1789             switch (message.what) {
1790                 case CMD_RECEIVE_IKE_PACKET:
1791                     handleReceivedIkePacket(message);
1792                     return HANDLED;
1793                 case CMD_ALARM_FIRED:
1794                     handleFiredAlarm(message);
1795                     return HANDLED;
1796                 case CMD_FORCE_TRANSITION:
1797                     transitionTo((State) message.obj);
1798                     return HANDLED;
1799 
1800                 case CMD_EXECUTE_LOCAL_REQ:
1801                     logWtf("Invalid execute local request command in non-idle state");
1802                     return NOT_HANDLED;
1803 
1804                 case CMD_RETRANSMIT:
1805                     triggerRetransmit();
1806                     return HANDLED;
1807 
1808                 case CMD_SET_NETWORK:
1809                     if (!mIkeConnectionCtrl.isMobilityEnabled()) {
1810                         logi("setNetwork() called for session without mobility support.");
1811 
1812                         // TODO(b/224686889): Notify caller of failed mobility attempt.
1813                         return HANDLED;
1814                     }
1815 
1816                     try {
1817                         final NetworkParams params = (NetworkParams) message.obj;
1818                         mIkeConnectionCtrl.onNetworkSetByUser(
1819                                 params.network,
1820                                 params.ipVersion,
1821                                 params.encapType,
1822                                 params.keepaliveDelaySeconds);
1823                     } catch (IkeException e) {
1824                         handleIkeFatalError(e);
1825                     }
1826                     return HANDLED;
1827 
1828                 case CMD_SET_UNDERPINNED_NETWORK:
1829                     try {
1830                         mIkeConnectionCtrl.onUnderpinnedNetworkSetByUser((Network) message.obj);
1831                     } catch (IkeException e) {
1832                         handleIkeFatalError(e);
1833                     }
1834                     return HANDLED;
1835 
1836                 default:
1837                     // Queue local requests, and trigger next procedure
1838                     if (isLocalRequest(message.what)) {
1839                         handleLocalRequest(message.what, (LocalRequest) message.obj);
1840                         return HANDLED;
1841                     }
1842                     return NOT_HANDLED;
1843             }
1844         }
1845 
1846         /**
1847          * Handler for retransmission timer firing
1848          *
1849          * <p>By default, the trigger is logged and dropped. States that have a retransmitter should
1850          * override this function, and proxy the call to Retransmitter.retransmit()
1851          */
triggerRetransmit()1852         protected void triggerRetransmit() {
1853             logWtf("Retransmission trigger dropped in state: " + this.getClass().getSimpleName());
1854         }
1855 
getIkeSaRecordForPacket(IkeHeader ikeHeader)1856         protected IkeSaRecord getIkeSaRecordForPacket(IkeHeader ikeHeader) {
1857             if (ikeHeader.fromIkeInitiator) {
1858                 return mLocalSpiToIkeSaRecordMap.get(ikeHeader.ikeResponderSpi);
1859             } else {
1860                 return mLocalSpiToIkeSaRecordMap.get(ikeHeader.ikeInitiatorSpi);
1861             }
1862         }
1863 
handleReceivedIkePacket(Message message)1864         protected void handleReceivedIkePacket(Message message) {
1865             // TODO: b/138411550 Notify subclasses when discarding a received packet. Receiving MUST
1866             // go back to Idle state in this case.
1867 
1868             String methodTag = "handleReceivedIkePacket: ";
1869 
1870             ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
1871             IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
1872             byte[] ikePacketBytes = receivedIkePacket.ikePacketBytes;
1873             IkeSaRecord ikeSaRecord = getIkeSaRecordForPacket(ikeHeader);
1874 
1875             String msgDirection = ikeHeader.isResponseMsg ? "response" : "request";
1876 
1877             // Drop packets that we don't have an SA for:
1878             if (ikeSaRecord == null) {
1879                 // TODO: Print a summary of the IKE message (perhaps the IKE header)
1880                 cleanUpAndQuit(
1881                         new IllegalStateException(
1882                                 "Received an IKE "
1883                                         + msgDirection
1884                                         + "but found no matching SA for it"));
1885                 return;
1886             }
1887 
1888             logd(
1889                     methodTag
1890                             + "Received an "
1891                             + ikeHeader.getBasicInfoString()
1892                             + " on IKE SA with local SPI: "
1893                             + ikeSaRecord.getLocalSpi()
1894                             + ". Packet size: "
1895                             + ikePacketBytes.length);
1896 
1897             if (ikeHeader.isResponseMsg) {
1898                 int expectedMsgId = ikeSaRecord.getLocalRequestMessageId();
1899                 if (expectedMsgId - 1 == ikeHeader.messageId) {
1900                     logd(methodTag + "Received re-transmitted response. Discard it.");
1901                     return;
1902                 }
1903 
1904                 DecodeResult decodeResult =
1905                         IkeMessage.decode(
1906                                 expectedMsgId,
1907                                 mIkeIntegrity,
1908                                 mIkeCipher,
1909                                 ikeSaRecord,
1910                                 ikeHeader,
1911                                 ikePacketBytes,
1912                                 ikeSaRecord.getCollectedFragments(true /*isResp*/));
1913                 switch (decodeResult.status) {
1914                     case DECODE_STATUS_OK:
1915                         ikeSaRecord.incrementLocalRequestMessageId();
1916                         ikeSaRecord.resetCollectedFragments(true /*isResp*/);
1917 
1918                         DecodeResultOk resultOk = (DecodeResultOk) decodeResult;
1919                         if (isTempFailure(resultOk.ikeMessage)) {
1920                             handleTempFailure();
1921                         } else {
1922                             mTempFailHandler.reset();
1923                         }
1924 
1925                         handleResponseIkeMessage(resultOk.ikeMessage);
1926                         break;
1927                     case DECODE_STATUS_PARTIAL:
1928                         ikeSaRecord.updateCollectedFragments(
1929                                 (DecodeResultPartial) decodeResult, true /*isResp*/);
1930                         break;
1931                     case DECODE_STATUS_PROTECTED_ERROR:
1932                         IkeException ikeException = ((DecodeResultError) decodeResult).ikeException;
1933                         logi(methodTag + "Protected error", ikeException);
1934 
1935                         ikeSaRecord.incrementLocalRequestMessageId();
1936                         ikeSaRecord.resetCollectedFragments(true /*isResp*/);
1937 
1938                         handleResponseGenericProcessError(
1939                                 ikeSaRecord,
1940                                 new InvalidSyntaxException(
1941                                         "Generic processing error in the received response",
1942                                         ikeException));
1943                         break;
1944                     case DECODE_STATUS_UNPROTECTED_ERROR:
1945                         logi(
1946                                 methodTag
1947                                         + "Message authentication or decryption failed on received"
1948                                         + " response. Discard it",
1949                                 ((DecodeResultError) decodeResult).ikeException);
1950                         break;
1951                     default:
1952                         cleanUpAndQuit(
1953                                 new IllegalStateException(
1954                                         "Unrecognized decoding status: " + decodeResult.status));
1955                 }
1956 
1957             } else {
1958                 int expectedMsgId = ikeSaRecord.getRemoteRequestMessageId();
1959                 if (expectedMsgId - 1 == ikeHeader.messageId) {
1960                     if (ikeSaRecord.isRetransmittedRequest(ikePacketBytes)) {
1961                         if (ikeSaRecord.getLastSentRespMsgId() == ikeHeader.messageId) {
1962                             logd(
1963                                     "Received re-transmitted request "
1964                                             + ikeHeader.messageId
1965                                             + " Retransmitting response");
1966                             for (byte[] packet : ikeSaRecord.getLastSentRespAllPackets()) {
1967                                 mIkeConnectionCtrl.sendIkePacket(packet);
1968                             }
1969                         } else {
1970                             logd(
1971                                     "Received re-transmitted request "
1972                                             + ikeHeader.messageId
1973                                             + " Original request is still being processed");
1974                         }
1975 
1976                         // TODO:Support resetting remote rekey delete timer.
1977                     } else {
1978                         logi(methodTag + "Received a request with invalid message ID. Discard it.");
1979                     }
1980                 } else {
1981                     DecodeResult decodeResult =
1982                             IkeMessage.decode(
1983                                     expectedMsgId,
1984                                     mIkeIntegrity,
1985                                     mIkeCipher,
1986                                     ikeSaRecord,
1987                                     ikeHeader,
1988                                     ikePacketBytes,
1989                                     ikeSaRecord.getCollectedFragments(false /*isResp*/));
1990                     switch (decodeResult.status) {
1991                         case DECODE_STATUS_OK:
1992                             ikeSaRecord.incrementRemoteRequestMessageId();
1993                             ikeSaRecord.resetCollectedFragments(false /*isResp*/);
1994 
1995                             DecodeResultOk resultOk = (DecodeResultOk) decodeResult;
1996                             IkeMessage ikeMessage = resultOk.ikeMessage;
1997                             ikeSaRecord.updateLastReceivedReqFirstPacket(resultOk.firstPacket);
1998 
1999                             // Handle DPD here.
2000                             if (ikeMessage.isDpdRequest()) {
2001                                 logd(methodTag + "Received DPD request");
2002                                 IkeMessage dpdResponse =
2003                                         buildEncryptedInformationalMessage(
2004                                                 ikeSaRecord,
2005                                                 new IkeInformationalPayload[] {},
2006                                                 true,
2007                                                 ikeHeader.messageId);
2008                                 sendEncryptedIkeMessage(ikeSaRecord, dpdResponse);
2009                                 break;
2010                             }
2011 
2012                             int ikeExchangeSubType = ikeMessage.getIkeExchangeSubType();
2013                             logd(
2014                                     methodTag
2015                                             + "Request exchange subtype: "
2016                                             + IkeMessage.getIkeExchangeSubTypeString(
2017                                                     ikeExchangeSubType));
2018 
2019                             if (ikeExchangeSubType == IKE_EXCHANGE_SUBTYPE_INVALID
2020                                     || ikeExchangeSubType == IKE_EXCHANGE_SUBTYPE_IKE_INIT
2021                                     || ikeExchangeSubType == IKE_EXCHANGE_SUBTYPE_IKE_AUTH) {
2022 
2023                                 // Reply with INVALID_SYNTAX and close IKE Session.
2024                                 buildAndSendErrorNotificationResponse(
2025                                         mCurrentIkeSaRecord,
2026                                         ikeHeader.messageId,
2027                                         ERROR_TYPE_INVALID_SYNTAX);
2028                                 handleIkeFatalError(
2029                                         new InvalidSyntaxException(
2030                                                 "Cannot handle message with invalid or unexpected"
2031                                                         + " IkeExchangeSubType: "
2032                                                         + ikeExchangeSubType));
2033                                 return;
2034                             }
2035                             handleRequestIkeMessage(ikeMessage, ikeExchangeSubType, message);
2036                             break;
2037                         case DECODE_STATUS_PARTIAL:
2038                             ikeSaRecord.updateCollectedFragments(
2039                                     (DecodeResultPartial) decodeResult, false /*isResp*/);
2040                             break;
2041                         case DECODE_STATUS_PROTECTED_ERROR:
2042                             DecodeResultProtectedError resultError =
2043                                     (DecodeResultProtectedError) decodeResult;
2044 
2045                             IkeException ikeException = resultError.ikeException;
2046                             logi(methodTag + "Protected error", resultError.ikeException);
2047 
2048                             ikeSaRecord.incrementRemoteRequestMessageId();
2049                             ikeSaRecord.resetCollectedFragments(false /*isResp*/);
2050 
2051                             ikeSaRecord.updateLastReceivedReqFirstPacket(resultError.firstPacket);
2052 
2053                             // IkeException MUST be already wrapped into an IkeProtocolException
2054                             handleRequestGenericProcessError(
2055                                     ikeSaRecord,
2056                                     ikeHeader.messageId,
2057                                     (IkeProtocolException) ikeException);
2058                             break;
2059                         case DECODE_STATUS_UNPROTECTED_ERROR:
2060                             logi(
2061                                     methodTag
2062                                             + "Message authentication or decryption failed on"
2063                                             + " received request. Discard it",
2064                                     ((DecodeResultError) decodeResult).ikeException);
2065                             break;
2066                         default:
2067                             cleanUpAndQuit(
2068                                     new IllegalStateException(
2069                                             "Unrecognized decoding status: "
2070                                                     + decodeResult.status));
2071                     }
2072                 }
2073             }
2074         }
2075 
isTempFailure(IkeMessage message)2076         private boolean isTempFailure(IkeMessage message) {
2077             List<IkeNotifyPayload> notifyPayloads =
2078                     message.getPayloadListForType(PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
2079 
2080             for (IkeNotifyPayload notify : notifyPayloads) {
2081                 if (notify.notifyType == ERROR_TYPE_TEMPORARY_FAILURE) {
2082                     return true;
2083                 }
2084             }
2085             return false;
2086         }
2087 
handleTempFailure()2088         protected void handleTempFailure() {
2089             // Log and close IKE Session due to unexpected TEMPORARY_FAILURE. This error should
2090             // only occur during CREATE_CHILD_SA exchange.
2091             handleIkeFatalError(
2092                     new InvalidSyntaxException("Received unexpected TEMPORARY_FAILURE"));
2093 
2094             // States that accept a TEMPORARY MUST override this method to schedule a retry.
2095         }
2096 
handleGenericInfoRequest(IkeMessage ikeMessage)2097         protected void handleGenericInfoRequest(IkeMessage ikeMessage) {
2098             try {
2099                 List<IkeInformationalPayload> infoPayloadList = new ArrayList<>();
2100                 for (IkePayload payload : ikeMessage.ikePayloadList) {
2101                     switch (payload.payloadType) {
2102                         case PAYLOAD_TYPE_CP:
2103                             // TODO(b/150327849): Respond with config payload responses.
2104                             break;
2105                         case PAYLOAD_TYPE_NOTIFY:
2106                             IkeNotifyPayload notify = (IkeNotifyPayload) payload;
2107                             if (notify.notifyType == NOTIFY_TYPE_COOKIE2) {
2108                                 infoPayloadList.add(
2109                                         IkeNotifyPayload.handleCookie2AndGenerateCopy(notify));
2110                             }
2111 
2112                             // No action for other notifications
2113                             break;
2114                         default:
2115                             logw(
2116                                     "Received unexpected payload in an INFORMATIONAL request."
2117                                             + " Payload type: "
2118                                             + payload.payloadType);
2119                     }
2120                 }
2121 
2122                 // add any 3GPP informational payloads if needed
2123                 List<IkePayload> ikePayloads =
2124                         mIke3gppExtensionExchange.getResponsePayloads(
2125                                 IKE_EXCHANGE_SUBTYPE_GENERIC_INFO, ikeMessage.ikePayloadList);
2126                 for (IkePayload payload : ikePayloads) {
2127                     if (payload instanceof IkeInformationalPayload) {
2128                         infoPayloadList.add((IkeInformationalPayload) payload);
2129                     } else {
2130                         logd(
2131                                 "Ignoring unexpected payload that is not an IkeInformationalPayload"
2132                                         + payload);
2133                     }
2134                 }
2135 
2136                 IkeMessage infoResp =
2137                         buildEncryptedInformationalMessage(
2138                                 infoPayloadList.toArray(
2139                                         new IkeInformationalPayload[infoPayloadList.size()]),
2140                                 true /* isResponse */,
2141                                 ikeMessage.ikeHeader.messageId);
2142                 sendEncryptedIkeMessage(infoResp);
2143             } catch (InvalidSyntaxException e) {
2144                 buildAndSendErrorNotificationResponse(
2145                         mCurrentIkeSaRecord,
2146                         ikeMessage.ikeHeader.messageId,
2147                         ERROR_TYPE_INVALID_SYNTAX);
2148                 handleIkeFatalError(e);
2149                 return;
2150             }
2151         }
2152 
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)2153         protected void handleRequestIkeMessage(
2154                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
2155             // Subclasses MUST override it if they care
2156             cleanUpAndQuit(
2157                     new IllegalStateException(
2158                             "Do not support handling an encrypted request: " + ikeExchangeSubType));
2159         }
2160 
handleResponseIkeMessage(IkeMessage ikeMessage)2161         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
2162             // Subclasses MUST override it if they care
2163             cleanUpAndQuit(
2164                     new IllegalStateException("Do not support handling an encrypted response"));
2165         }
2166 
2167         /**
2168          * Method for handling generic processing error of a request.
2169          *
2170          * <p>A generic processing error is usally syntax error, unsupported critical payload error
2171          * and major version error. IKE SA that should reply with corresponding error notifications
2172          */
handleRequestGenericProcessError( IkeSaRecord ikeSaRecord, int messageId, IkeProtocolException exception)2173         protected void handleRequestGenericProcessError(
2174                 IkeSaRecord ikeSaRecord, int messageId, IkeProtocolException exception) {
2175             IkeNotifyPayload errNotify = exception.buildNotifyPayload();
2176             sendEncryptedIkeMessage(
2177                     ikeSaRecord,
2178                     buildEncryptedInformationalMessage(
2179                             ikeSaRecord,
2180                             new IkeInformationalPayload[] {errNotify},
2181                             true /*isResponse*/,
2182                             messageId));
2183 
2184             // Receiver of INVALID_SYNTAX error notification should delete the IKE SA
2185             if (exception.getErrorType() == ERROR_TYPE_INVALID_SYNTAX) {
2186                 handleIkeFatalError(exception);
2187             }
2188         }
2189 
2190         /**
2191          * Method for handling generic processing error of a response.
2192          *
2193          * <p>Detailed error is wrapped in the InvalidSyntaxException, which is usally syntax error,
2194          * unsupported critical payload error and major version error. IKE SA that receives a
2195          * response with these errors should be closed.
2196          */
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException)2197         protected void handleResponseGenericProcessError(
2198                 IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
2199             // Subclasses MUST override it if they care
2200             cleanUpAndQuit(
2201                     new IllegalStateException(
2202                             "Do not support handling generic processing error of encrypted"
2203                                     + " response"));
2204         }
2205 
2206         /**
2207          * Method for handling and extracting 3GPP-specific payloads from the IKE response payloads.
2208          *
2209          * <p>Returns the extracted 3GPP payloads after they have been handled. Only non
2210          * error-notify payloads are returned.
2211          */
handle3gppRespAndExtractNonError3gppPayloads( int exchangeSubtype, List<IkePayload> respPayloads)2212         protected List<IkePayload> handle3gppRespAndExtractNonError3gppPayloads(
2213                 int exchangeSubtype, List<IkePayload> respPayloads) throws InvalidSyntaxException {
2214             List<IkePayload> ike3gppPayloads =
2215                     mIke3gppExtensionExchange.extract3gppResponsePayloads(
2216                             exchangeSubtype, respPayloads);
2217 
2218             mIke3gppExtensionExchange.handle3gppResponsePayloads(exchangeSubtype, ike3gppPayloads);
2219 
2220             List<IkePayload> ike3gppErrorNotifyPayloads = new ArrayList<>();
2221             for (IkePayload payload : ike3gppPayloads) {
2222                 if (payload instanceof IkeNotifyPayload) {
2223                     IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
2224                     if (notifyPayload.isErrorNotify()) {
2225                         ike3gppErrorNotifyPayloads.add(payload);
2226                     }
2227                 }
2228             }
2229             ike3gppPayloads.removeAll(ike3gppErrorNotifyPayloads);
2230 
2231             return ike3gppPayloads;
2232         }
2233     }
2234 
2235     /**
2236      * Retransmitter represents a RAII class to send the initial request, and retransmit as needed.
2237      *
2238      * <p>The Retransmitter class will automatically start transmission upon creation.
2239      */
2240     @VisibleForTesting
2241     class EncryptedRetransmitter extends Retransmitter {
2242         private final byte[][] mIkePacketList;
2243 
2244         @VisibleForTesting
EncryptedRetransmitter(IkeMessage msg)2245         EncryptedRetransmitter(IkeMessage msg) {
2246             this(mCurrentIkeSaRecord, msg);
2247         }
2248 
EncryptedRetransmitter(IkeSaRecord ikeSaRecord, IkeMessage msg)2249         private EncryptedRetransmitter(IkeSaRecord ikeSaRecord, IkeMessage msg) {
2250             super(getHandler(), msg, mIkeSessionParams.getRetransmissionTimeoutsMillis());
2251             mIkePacketList =
2252                     msg.encryptAndEncode(
2253                             mIkeIntegrity,
2254                             mIkeCipher,
2255                             ikeSaRecord,
2256                             mEnabledExtensions.contains(EXTENSION_TYPE_FRAGMENTATION),
2257                             DEFAULT_FRAGMENT_SIZE);
2258 
2259             retransmit();
2260         }
2261 
2262         @Override
send()2263         public void send() {
2264             sendEncryptedIkePackets(mIkePacketList);
2265         }
2266 
2267         @Override
handleRetransmissionFailure()2268         public void handleRetransmissionFailure() {
2269             handleIkeFatalError(
2270                     ShimUtils.getInstance()
2271                             .getRetransmissionFailedException("Retransmitting failure"));
2272         }
2273     }
2274 
2275     /**
2276      * DeleteResponderBase represents all states after IKE_INIT and IKE_AUTH.
2277      *
2278      * <p>All post-init states share common functionality of being able to respond to IKE_DELETE
2279      * requests.
2280      */
2281     private abstract class DeleteResponderBase extends BusyState {
2282         /** Builds a IKE Delete Response for the given IKE SA and request. */
buildIkeDeleteResp(IkeMessage req, IkeSaRecord ikeSaRecord)2283         protected IkeMessage buildIkeDeleteResp(IkeMessage req, IkeSaRecord ikeSaRecord) {
2284             IkeInformationalPayload[] payloads = new IkeInformationalPayload[] {};
2285             return buildEncryptedInformationalMessage(
2286                     ikeSaRecord, payloads, true /* isResp */, req.ikeHeader.messageId);
2287         }
2288 
2289         /**
2290          * Validates that the delete request is acceptable.
2291          *
2292          * <p>The request message must be guaranteed by previous checks to be of SUBTYPE_DELETE_IKE,
2293          * and therefore contains an IkeDeletePayload. This is checked in getIkeExchangeSubType.
2294          */
validateIkeDeleteReq(IkeMessage req, IkeSaRecord expectedRecord)2295         protected void validateIkeDeleteReq(IkeMessage req, IkeSaRecord expectedRecord)
2296                 throws InvalidSyntaxException {
2297             if (expectedRecord != getIkeSaRecordForPacket(req.ikeHeader)) {
2298                 throw new InvalidSyntaxException("Delete request received in wrong SA");
2299             }
2300         }
2301 
2302         /**
2303          * Helper method for responding to a session deletion request
2304          *
2305          * <p>Note that this method expects that the session is keyed on the current IKE SA session,
2306          * and closing the IKE SA indicates that the remote wishes to end the session as a whole. As
2307          * such, this should not be used in rekey cases where there is any ambiguity as to which IKE
2308          * SA the session is reliant upon.
2309          *
2310          * <p>Note that this method will also quit the state machine.
2311          *
2312          * @param ikeMessage The received session deletion request
2313          */
handleDeleteSessionRequest(IkeMessage ikeMessage)2314         protected void handleDeleteSessionRequest(IkeMessage ikeMessage) {
2315             try {
2316                 validateIkeDeleteReq(ikeMessage, mCurrentIkeSaRecord);
2317                 IkeMessage resp = buildIkeDeleteResp(ikeMessage, mCurrentIkeSaRecord);
2318 
2319                 executeUserCallback(
2320                         () -> {
2321                             mIkeSessionCallback.onClosed();
2322                         });
2323 
2324                 sendEncryptedIkeMessage(mCurrentIkeSaRecord, resp);
2325 
2326                 removeIkeSaRecord(mCurrentIkeSaRecord);
2327                 mCurrentIkeSaRecord.close();
2328                 mCurrentIkeSaRecord = null;
2329 
2330                 quitSessionNow();
2331             } catch (InvalidSyntaxException e) {
2332                 // Got deletion of a non-Current IKE SA. Program error.
2333                 cleanUpAndQuit(new IllegalStateException(e));
2334             }
2335         }
2336     }
2337 
2338     /**
2339      * DeleteBase abstracts deletion handling for all states initiating a delete exchange
2340      *
2341      * <p>All subclasses of this state share common functionality that a deletion request is sent,
2342      * and the response is received.
2343      */
2344     private abstract class DeleteBase extends DeleteResponderBase {
validateIkeDeleteResp(IkeMessage resp, IkeSaRecord expectedSaRecord)2345         protected void validateIkeDeleteResp(IkeMessage resp, IkeSaRecord expectedSaRecord)
2346                 throws InvalidSyntaxException {
2347             if (expectedSaRecord != getIkeSaRecordForPacket(resp.ikeHeader)) {
2348                 throw new IllegalStateException("Response received on incorrect SA");
2349             }
2350 
2351             if (resp.ikeHeader.exchangeType != IkeHeader.EXCHANGE_TYPE_INFORMATIONAL) {
2352                 throw new InvalidSyntaxException(
2353                         "Invalid exchange type; expected INFORMATIONAL, but got: "
2354                                 + resp.ikeHeader.exchangeType);
2355             }
2356 
2357             if (!resp.ikePayloadList.isEmpty()) {
2358                 throw new InvalidSyntaxException(
2359                         "Unexpected payloads - IKE Delete response should be empty.");
2360             }
2361         }
2362     }
2363 
2364     /**
2365      * Receiving represents a state when idle IkeSessionStateMachine receives an incoming packet.
2366      *
2367      * <p>If this incoming packet is fully handled by Receiving state and does not trigger any
2368      * further state transition or deletion of whole IKE Session, IkeSessionStateMachine MUST
2369      * transition back to Idle.
2370      */
2371     class Receiving extends RekeyIkeHandlerBase {
2372         private boolean mProcedureFinished = true;
2373 
2374         @Override
enterState()2375         public void enterState() {
2376             mProcedureFinished = true;
2377         }
2378 
2379         @Override
handleReceivedIkePacket(Message message)2380         protected void handleReceivedIkePacket(Message message) {
2381             super.handleReceivedIkePacket(message);
2382 
2383             // If the IKE process triggered by the received packet is completed in this
2384             // state, transition back to Idle. Otherwise, either stay in this state, or transition
2385             // to another state specified in #handleRequestIkeMessage.
2386             if (mProcedureFinished) transitionTo(mIdle);
2387         }
2388 
2389         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)2390         protected void handleRequestIkeMessage(
2391                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
2392             switch (ikeExchangeSubType) {
2393                 case IKE_EXCHANGE_SUBTYPE_REKEY_IKE:
2394                     // Errors in this exchange with no specific protocol error code will all be
2395                     // classified to use NO_PROPOSAL_CHOSEN. The reason that we don't use
2396                     // NO_ADDITIONAL_SAS is because it indicates "responder is unwilling to accept
2397                     // any more Child SAs on this IKE SA.", according to RFC 7296. Sending this
2398                     // error may mislead the remote peer.
2399                     try {
2400                         validateIkeRekeyReq(ikeMessage);
2401 
2402                         // Build a rekey response payload with our previously selected proposal,
2403                         // against which we will validate the received proposals. Re-negotiating
2404                         // proposal with different algorithms is not supported since there
2405                         // is no use case.
2406                         IkeSaPayload reqSaPayload =
2407                                 ikeMessage.getPayloadForType(
2408                                         IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
2409                         byte respProposalNumber =
2410                                 reqSaPayload.getNegotiatedProposalNumber(mSaProposal);
2411 
2412                         IkeKePayload reqKePayload =
2413                                 ikeMessage.getPayloadForType(
2414                                         IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
2415                         if (reqKePayload.dhGroup != mSaProposal.getDhGroups().get(0)) {
2416                             throw new InvalidKeException(mSaProposal.getDhGroups().get(0));
2417                         }
2418 
2419                         List<IkePayload> payloadList =
2420                                 CreateIkeSaHelper.getRekeyIkeSaResponsePayloads(
2421                                         respProposalNumber,
2422                                         mSaProposal,
2423                                         mIkeSpiGenerator,
2424                                         mIkeConnectionCtrl.getLocalAddress(),
2425                                         mIkeContext.getRandomnessFactory());
2426 
2427                         // Build IKE header
2428                         IkeHeader ikeHeader =
2429                                 new IkeHeader(
2430                                         mCurrentIkeSaRecord.getInitiatorSpi(),
2431                                         mCurrentIkeSaRecord.getResponderSpi(),
2432                                         IkePayload.PAYLOAD_TYPE_SK,
2433                                         IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
2434                                         true /*isResponseMsg*/,
2435                                         mCurrentIkeSaRecord.isLocalInit,
2436                                         ikeMessage.ikeHeader.messageId);
2437 
2438                         IkeMessage responseIkeMessage = new IkeMessage(ikeHeader, payloadList);
2439 
2440                         // Build new SA first to ensure that we can find a valid proposal.
2441                         mRemoteInitNewIkeSaRecord =
2442                                 validateAndBuildIkeSa(
2443                                         ikeMessage, responseIkeMessage, false /*isLocalInit*/);
2444 
2445                         sendEncryptedIkeMessage(responseIkeMessage);
2446 
2447                         transitionTo(mRekeyIkeRemoteDelete);
2448                         mProcedureFinished = false;
2449                     } catch (IkeProtocolException e) {
2450                         handleRekeyCreationFailure(ikeMessage.ikeHeader.messageId, e);
2451                     } catch (GeneralSecurityException e) {
2452                         handleRekeyCreationFailure(
2453                                 ikeMessage.ikeHeader.messageId,
2454                                 new NoValidProposalChosenException(
2455                                         "Error in building new IKE SA", e));
2456                     } catch (IOException e) {
2457                         handleRekeyCreationFailure(
2458                                 ikeMessage.ikeHeader.messageId,
2459                                 new NoValidProposalChosenException(
2460                                         "IKE SPI allocation collided - they reused an SPI.", e));
2461                     }
2462                     return;
2463                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
2464                     handleDeleteSessionRequest(ikeMessage);
2465 
2466                     // Directly quit from this state. Do not need to transition back to Idle state
2467                     mProcedureFinished = false;
2468                     return;
2469                 case IKE_EXCHANGE_SUBTYPE_CREATE_CHILD: // Fall through
2470                 case IKE_EXCHANGE_SUBTYPE_DELETE_CHILD: // Fall through
2471                 case IKE_EXCHANGE_SUBTYPE_REKEY_CHILD:
2472                     deferMessage(
2473                             obtainMessage(
2474                                     CMD_RECEIVE_REQUEST_FOR_CHILD,
2475                                     ikeExchangeSubType,
2476                                     0 /*placeHolder*/,
2477                                     ikeMessage));
2478                     transitionTo(mChildProcedureOngoing);
2479                     mProcedureFinished = false;
2480                     return;
2481                 case IKE_EXCHANGE_SUBTYPE_GENERIC_INFO:
2482                     handleGenericInfoRequest(ikeMessage);
2483                     return;
2484                 default:
2485             }
2486         }
2487 
handleRekeyCreationFailure(int messageId, IkeProtocolException e)2488         private void handleRekeyCreationFailure(int messageId, IkeProtocolException e) {
2489             loge("Received invalid Rekey IKE request. Reject with error notification", e);
2490 
2491             buildAndSendNotificationResponse(
2492                     mCurrentIkeSaRecord, messageId, e.buildNotifyPayload());
2493         }
2494     }
2495 
2496     /**
2497      * This class represents a state when there is at least one ongoing Child procedure
2498      * (Create/Rekey/Delete Child)
2499      *
2500      * <p>For a locally initiated Child procedure, this state is responsible for notifying Child
2501      * Session to initiate the exchange, building outbound request IkeMessage with Child Session
2502      * provided payload list and redirecting the inbound response to Child Session for validation.
2503      *
2504      * <p>For a remotely initiated Child procedure, this state is responsible for redirecting the
2505      * inbound request to Child Session(s) and building outbound response IkeMessage with Child
2506      * Session provided payload list. Exchange collision on a Child Session will be resolved inside
2507      * the Child Session.
2508      *
2509      * <p>For a remotely initiated IKE procedure, this state will only accept a Delete IKE request
2510      * and reject other types with TEMPORARY_FAILURE, since it causes conflict with the ongoing
2511      * Child procedure.
2512      *
2513      * <p>For most inbound request/response, this state will first pick out and handle IKE related
2514      * payloads and then send the rest of the payloads to Child Session for further validation. It
2515      * is the Child Session's responsibility to check required payloads (and verify the exchange
2516      * type) according to its procedure type. Only when receiving an inbound delete Child request,
2517      * as the only case where multiple Child Sessions will be affected by one IkeMessage, this state
2518      * will only send Delete Payload(s) to Child Session.
2519      */
2520     class ChildProcedureOngoing extends DeleteBase {
2521         // It is possible that mChildInLocalProcedure is also in mChildInRemoteProcedures when both
2522         // sides initiated exchange for the same Child Session.
2523         private ChildSessionStateMachine mChildInLocalProcedure;
2524         private Set<ChildSessionStateMachine> mChildInRemoteProcedures;
2525 
2526         private ChildLocalRequest mLocalRequestOngoing;
2527 
2528         // Keep a reference to the first Child SA request so that if IKE Session is killed before
2529         // first Child negotiation is done, ChildProcedureOngoing can release the IPSec SPI resource
2530         // using this reference.
2531         private List<IkePayload> mFirstChildReqList;
2532 
2533         private int mLastInboundRequestMsgId;
2534         private List<IkePayload> mOutboundRespPayloads;
2535         private Set<ChildSessionStateMachine> mAwaitingChildResponse;
2536 
2537         private EncryptedRetransmitter mRetransmitter;
2538 
2539         @Override
enterState()2540         public void enterState() {
2541             mChildInLocalProcedure = null;
2542             mChildInRemoteProcedures = new HashSet<>();
2543 
2544             mLocalRequestOngoing = null;
2545 
2546             mLastInboundRequestMsgId = 0;
2547             mOutboundRespPayloads = new LinkedList<>();
2548             mAwaitingChildResponse = new HashSet<>();
2549         }
2550 
2551         @Override
triggerRetransmit()2552         protected void triggerRetransmit() {
2553             mRetransmitter.retransmit();
2554         }
2555 
2556         @Override
processStateMessage(Message message)2557         public boolean processStateMessage(Message message) {
2558             switch (message.what) {
2559                 case CMD_RECEIVE_REQUEST_FOR_CHILD:
2560                     // Handle remote request (and do state transition)
2561                     handleRequestIkeMessage(
2562                             (IkeMessage) message.obj,
2563                             message.arg1 /*ikeExchangeSubType*/,
2564                             null /*ReceivedIkePacket*/);
2565                     return HANDLED;
2566                 case CMD_OUTBOUND_CHILD_PAYLOADS_READY:
2567                     ChildOutboundData outboundData = (ChildOutboundData) message.obj;
2568                     int exchangeType = outboundData.exchangeType;
2569                     List<IkePayload> outboundPayloads = outboundData.payloadList;
2570 
2571                     if (outboundData.isResp) {
2572                         handleOutboundResponse(
2573                                 exchangeType, outboundPayloads, outboundData.childSession);
2574                     } else {
2575                         handleOutboundRequest(exchangeType, outboundPayloads);
2576                     }
2577 
2578                     return HANDLED;
2579                 case CMD_CHILD_PROCEDURE_FINISHED:
2580                     ChildSessionStateMachine childSession = (ChildSessionStateMachine) message.obj;
2581 
2582                     if (mChildInLocalProcedure == childSession) {
2583                         mChildInLocalProcedure = null;
2584                         mLocalRequestOngoing = null;
2585                     }
2586                     mChildInRemoteProcedures.remove(childSession);
2587 
2588                     transitionToIdleIfAllProceduresDone();
2589                     return HANDLED;
2590                 case CMD_HANDLE_FIRST_CHILD_NEGOTIATION:
2591                     FirstChildNegotiationData childData = (FirstChildNegotiationData) message.obj;
2592                     mFirstChildReqList = childData.reqPayloads;
2593 
2594                     mChildInLocalProcedure = getChildSession(childData.childSessionCallback);
2595                     if (mChildInLocalProcedure == null) {
2596                         cleanUpAndQuit(new IllegalStateException("First child not found."));
2597                         return HANDLED;
2598                     }
2599 
2600                     mChildInLocalProcedure.handleFirstChildExchange(
2601                             childData.reqPayloads,
2602                             childData.respPayloads,
2603                             mIkeConnectionCtrl.getLocalAddress(),
2604                             mIkeConnectionCtrl.getRemoteAddress(),
2605                             getEncapSocketOrNull(),
2606                             mIkePrf,
2607                             mSaProposal.getDhGroupTransforms()[0].id, // negotiated DH
2608                             mCurrentIkeSaRecord.getSkD());
2609                     return HANDLED;
2610                 case CMD_EXECUTE_LOCAL_REQ:
2611                     executeLocalRequest((ChildLocalRequest) message.obj);
2612                     return HANDLED;
2613                 case CMD_KILL_SESSION:
2614                     // If mChildInLocalProcedure is null, there are no unfinished locally initiated
2615                     // procedures. It is safe to notify the remote that the session is being
2616                     // deleted.
2617                     if (mChildInLocalProcedure == null) {
2618                         // The delete notification is sent as a best-effort, so don't worry about
2619                         // retransmitting.
2620                         sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
2621                     }
2622 
2623                     // Let KillIkeSessionParent handle the rest of the cleanup.
2624                     return NOT_HANDLED;
2625                 case CMD_IKE_FATAL_ERROR_FROM_CHILD:
2626                     IkeFatalErrorFromChild fatalError = (IkeFatalErrorFromChild) message.obj;
2627                     handleIkeFatalError(fatalError.exception);
2628                     return HANDLED;
2629                 default:
2630                     return super.processStateMessage(message);
2631             }
2632         }
2633 
2634         @Override
exitState()2635         public void exitState() {
2636             if (mIsClosing && mFirstChildReqList != null) {
2637                 CreateChildSaHelper.releaseSpiResources(mFirstChildReqList);
2638             }
2639             super.exitState();
2640         }
2641 
2642         @Override
handleTempFailure()2643         protected void handleTempFailure() {
2644             // The ChildSessionStateMachine will be responsible for rescheduling the rejected
2645             // request.
2646             mTempFailHandler.handleTempFailure();
2647         }
2648 
transitionToIdleIfAllProceduresDone()2649         private void transitionToIdleIfAllProceduresDone() {
2650             if (mChildInLocalProcedure == null && mChildInRemoteProcedures.isEmpty()) {
2651                 transitionTo(mIdle);
2652             }
2653         }
2654 
getChildSession(ChildLocalRequest req)2655         private ChildSessionStateMachine getChildSession(ChildLocalRequest req) {
2656             if (req.childSessionCallback == null) {
2657                 return mRemoteSpiToChildSessionMap.get(req.remoteSpi);
2658             }
2659             return getChildSession(req.childSessionCallback);
2660         }
2661 
getChildSession(ChildSessionCallback callback)2662         private ChildSessionStateMachine getChildSession(ChildSessionCallback callback) {
2663             synchronized (mChildCbToSessions) {
2664                 return mChildCbToSessions.get(callback);
2665             }
2666         }
2667 
2668         // Returns the UDP-Encapsulation socket to the newly created ChildSessionStateMachine if
2669         // a NAT is detected or if NAT-T AND MOBIKE are enabled by both parties. It allows the
2670         // ChildSessionStateMachine to build IPsec transforms that can send and receive IPsec
2671         // traffic through a NAT.
getEncapSocketOrNull()2672         private UdpEncapsulationSocket getEncapSocketOrNull() {
2673             if (!mIkeConnectionCtrl.useUdpEncapSocket()) {
2674                 return null;
2675             }
2676             return ((IkeUdpEncapSocket) mIkeConnectionCtrl.getIkeSocket())
2677                     .getUdpEncapsulationSocket();
2678         }
2679 
executeLocalRequest(ChildLocalRequest req)2680         private void executeLocalRequest(ChildLocalRequest req) {
2681             req.releaseWakeLock();
2682             mChildInLocalProcedure = getChildSession(req);
2683             mLocalRequestOngoing = req;
2684 
2685             if (mChildInLocalProcedure == null) {
2686                 // This request has been validated to have a recognized target Child Session when
2687                 // it was sent to IKE Session at the begginnig. Failing to find this Child Session
2688                 // now means the Child creation has failed.
2689                 logd(
2690                         "Child state machine not found for local request: "
2691                                 + req.procedureType
2692                                 + " Creation of Child Session may have been failed.");
2693 
2694                 transitionToIdleIfAllProceduresDone();
2695                 return;
2696             }
2697             switch (req.procedureType) {
2698                 case CMD_LOCAL_REQUEST_CREATE_CHILD:
2699                     mChildInLocalProcedure.createChildSession(
2700                             mIkeConnectionCtrl.getLocalAddress(),
2701                             mIkeConnectionCtrl.getRemoteAddress(),
2702                             getEncapSocketOrNull(),
2703                             mIkePrf,
2704                             mSaProposal.getDhGroupTransforms()[0].id, // negotiated DH
2705                             mCurrentIkeSaRecord.getSkD());
2706                     break;
2707                 case CMD_LOCAL_REQUEST_REKEY_CHILD:
2708                     mChildInLocalProcedure.rekeyChildSession();
2709                     break;
2710                 case CMD_LOCAL_REQUEST_MIGRATE_CHILD:
2711                     mChildInLocalProcedure.performMigration(
2712                             mIkeConnectionCtrl.getLocalAddress(),
2713                             mIkeConnectionCtrl.getRemoteAddress(),
2714                             getEncapSocketOrNull());
2715                     break;
2716                 case CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE:
2717                     mChildInLocalProcedure.performRekeyMigration(
2718                             mIkeConnectionCtrl.getLocalAddress(),
2719                             mIkeConnectionCtrl.getRemoteAddress(),
2720                             getEncapSocketOrNull());
2721                     break;
2722                 case CMD_LOCAL_REQUEST_DELETE_CHILD:
2723                     mChildInLocalProcedure.deleteChildSession();
2724                     break;
2725                 default:
2726                     cleanUpAndQuit(
2727                             new IllegalStateException(
2728                                     "Invalid Child procedure type: " + req.procedureType));
2729                     break;
2730             }
2731         }
2732 
2733         /**
2734          * This method is called when this state receives an inbound request or when mReceiving
2735          * received an inbound Child request and deferred it to this state.
2736          */
2737         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)2738         protected void handleRequestIkeMessage(
2739                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
2740             // TODO: Grab a remote lock and hand payloads to the Child Session
2741 
2742             mLastInboundRequestMsgId = ikeMessage.ikeHeader.messageId;
2743             switch (ikeExchangeSubType) {
2744                 case IKE_EXCHANGE_SUBTYPE_CREATE_CHILD:
2745                     buildAndSendErrorNotificationResponse(
2746                             mCurrentIkeSaRecord,
2747                             ikeMessage.ikeHeader.messageId,
2748                             ERROR_TYPE_NO_ADDITIONAL_SAS);
2749                     break;
2750                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
2751                     // Send response and quit state machine
2752                     handleDeleteSessionRequest(ikeMessage);
2753 
2754                     // Return immediately to avoid transitioning to mIdle
2755                     return;
2756                 case IKE_EXCHANGE_SUBTYPE_DELETE_CHILD:
2757                     handleInboundDeleteChildRequest(ikeMessage);
2758                     break;
2759                 case IKE_EXCHANGE_SUBTYPE_REKEY_IKE:
2760                     buildAndSendErrorNotificationResponse(
2761                             mCurrentIkeSaRecord,
2762                             ikeMessage.ikeHeader.messageId,
2763                             ERROR_TYPE_TEMPORARY_FAILURE);
2764                     break;
2765                 case IKE_EXCHANGE_SUBTYPE_REKEY_CHILD:
2766                     handleInboundRekeyChildRequest(ikeMessage);
2767                     break;
2768                 case IKE_EXCHANGE_SUBTYPE_GENERIC_INFO:
2769                     handleGenericInfoRequest(ikeMessage);
2770                     break;
2771                 default:
2772                     cleanUpAndQuit(
2773                             new IllegalStateException(
2774                                     "Invalid IKE exchange subtype: " + ikeExchangeSubType));
2775                     return;
2776             }
2777             transitionToIdleIfAllProceduresDone();
2778         }
2779 
2780         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)2781         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
2782             mRetransmitter.stopRetransmitting();
2783 
2784             List<IkePayload> handledPayloads = new LinkedList<>();
2785 
2786             for (IkePayload payload : ikeMessage.ikePayloadList) {
2787                 switch (payload.payloadType) {
2788                     case PAYLOAD_TYPE_NOTIFY:
2789                         // TODO: Handle fatal IKE error notification and IKE status notification.
2790                         break;
2791                     case PAYLOAD_TYPE_VENDOR:
2792                         // TODO: Handle Vendor ID Payload
2793                         handledPayloads.add(payload);
2794                         break;
2795                     case PAYLOAD_TYPE_CP:
2796                         // TODO: Handle IKE related configuration attributes and pass the payload to
2797                         // Child to further handle internal IP address attributes.
2798                         break;
2799                     default:
2800                         break;
2801                 }
2802             }
2803 
2804             List<IkePayload> payloads = new LinkedList<>();
2805             payloads.addAll(ikeMessage.ikePayloadList);
2806             payloads.removeAll(handledPayloads);
2807 
2808             mChildInLocalProcedure.receiveResponse(ikeMessage.ikeHeader.exchangeType, payloads);
2809         }
2810 
2811         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException)2812         protected void handleResponseGenericProcessError(
2813                 IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
2814             mRetransmitter.stopRetransmitting();
2815 
2816             sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
2817             handleIkeFatalError(ikeException);
2818         }
2819 
handleInboundDeleteChildRequest(IkeMessage ikeMessage)2820         private void handleInboundDeleteChildRequest(IkeMessage ikeMessage) {
2821             // It is guaranteed in #getIkeExchangeSubType that at least one Delete Child Payload
2822             // exists.
2823 
2824             HashMap<ChildSessionStateMachine, List<IkePayload>> childToDelPayloadsMap =
2825                     new HashMap<>();
2826             Set<Integer> spiHandled = new HashSet<>();
2827 
2828             for (IkePayload payload : ikeMessage.ikePayloadList) {
2829                 switch (payload.payloadType) {
2830                     case PAYLOAD_TYPE_VENDOR:
2831                         // TODO: Investigate if Vendor ID Payload can be in an INFORMATIONAL
2832                         // message.
2833                         break;
2834                     case PAYLOAD_TYPE_NOTIFY:
2835                         logw(
2836                                 "Unexpected or unknown notification: "
2837                                         + ((IkeNotifyPayload) payload).notifyType);
2838                         break;
2839                     case PAYLOAD_TYPE_DELETE:
2840                         IkeDeletePayload delPayload = (IkeDeletePayload) payload;
2841 
2842                         for (int spi : delPayload.spisToDelete) {
2843                             ChildSessionStateMachine child = mRemoteSpiToChildSessionMap.get(spi);
2844                             if (child == null) {
2845                                 // TODO: Investigate how other implementations handle that.
2846                                 logw("Child SA not found with received SPI: " + spi);
2847                             } else if (!spiHandled.add(spi)) {
2848                                 logw("Received repeated Child SPI: " + spi);
2849                             } else {
2850                                 // Store Delete Payload with its target ChildSession
2851                                 if (!childToDelPayloadsMap.containsKey(child)) {
2852                                     childToDelPayloadsMap.put(child, new LinkedList<>());
2853                                 }
2854                                 List<IkePayload> delPayloads = childToDelPayloadsMap.get(child);
2855 
2856                                 // Avoid storing repeated Delete Payload
2857                                 if (!delPayloads.contains(delPayload)) delPayloads.add(delPayload);
2858                             }
2859                         }
2860 
2861                         break;
2862                     case PAYLOAD_TYPE_CP:
2863                         // TODO: Handle it
2864                         break;
2865                     default:
2866                         logw("Unexpected payload types found: " + payload.payloadType);
2867                 }
2868             }
2869 
2870             // If no Child SA is found, only reply with IKE related payloads or an empty
2871             // message
2872             if (childToDelPayloadsMap.isEmpty()) {
2873                 logd("No Child SA is found for this request.");
2874                 sendEncryptedIkeMessage(
2875                         buildEncryptedInformationalMessage(
2876                                 new IkeInformationalPayload[0],
2877                                 true /*isResp*/,
2878                                 ikeMessage.ikeHeader.messageId));
2879                 return;
2880             }
2881 
2882             // Send Delete Payloads to Child Sessions
2883             for (ChildSessionStateMachine child : childToDelPayloadsMap.keySet()) {
2884                 child.receiveRequest(
2885                         IKE_EXCHANGE_SUBTYPE_DELETE_CHILD,
2886                         EXCHANGE_TYPE_INFORMATIONAL,
2887                         childToDelPayloadsMap.get(child));
2888                 mAwaitingChildResponse.add(child);
2889                 mChildInRemoteProcedures.add(child);
2890             }
2891         }
2892 
handleInboundRekeyChildRequest(IkeMessage ikeMessage)2893         private void handleInboundRekeyChildRequest(IkeMessage ikeMessage) {
2894             // It is guaranteed in #getIkeExchangeSubType that at least one Notify-Rekey Child
2895             // Payload exists.
2896             List<IkePayload> handledPayloads = new LinkedList<>();
2897             ChildSessionStateMachine targetChild = null;
2898             Set<Integer> unrecognizedSpis = new HashSet<>();
2899 
2900             for (IkePayload payload : ikeMessage.ikePayloadList) {
2901                 switch (payload.payloadType) {
2902                     case PAYLOAD_TYPE_VENDOR:
2903                         // TODO: Handle it.
2904                         handledPayloads.add(payload);
2905                         break;
2906                     case PAYLOAD_TYPE_NOTIFY:
2907                         IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
2908                         if (NOTIFY_TYPE_REKEY_SA != notifyPayload.notifyType) break;
2909 
2910                         int childSpi = notifyPayload.spi;
2911                         ChildSessionStateMachine child = mRemoteSpiToChildSessionMap.get(childSpi);
2912 
2913                         if (child == null) {
2914                             // Remember unrecognized SPIs and reply error notification if no
2915                             // recognized SPI found.
2916                             unrecognizedSpis.add(childSpi);
2917                             logw("Child SA not found with received SPI: " + childSpi);
2918                         } else if (targetChild == null) {
2919                             // Each message should have only one Notify-Rekey Payload. If there are
2920                             // multiple of them, we only process the first valid one and ignore
2921                             // others.
2922                             targetChild = mRemoteSpiToChildSessionMap.get(childSpi);
2923                         } else {
2924                             logw("More than one Notify-Rekey Payload found with SPI: " + childSpi);
2925                             handledPayloads.add(notifyPayload);
2926                         }
2927                         break;
2928                     case PAYLOAD_TYPE_CP:
2929                         // TODO: Handle IKE related configuration attributes and pass the payload to
2930                         // Child to further handle internal IP address attributes.
2931                         break;
2932                     default:
2933                         break;
2934                 }
2935             }
2936 
2937             // Reject request with error notification.
2938             if (targetChild == null) {
2939                 IkeInformationalPayload[] errorPayloads =
2940                         new IkeInformationalPayload[unrecognizedSpis.size()];
2941                 int i = 0;
2942                 for (Integer spi : unrecognizedSpis) {
2943                     errorPayloads[i++] =
2944                             new IkeNotifyPayload(
2945                                     IkePayload.PROTOCOL_ID_ESP,
2946                                     spi,
2947                                     ERROR_TYPE_CHILD_SA_NOT_FOUND,
2948                                     new byte[0]);
2949                 }
2950 
2951                 IkeMessage msg =
2952                         buildEncryptedNotificationMessage(
2953                                 mCurrentIkeSaRecord,
2954                                 errorPayloads,
2955                                 EXCHANGE_TYPE_INFORMATIONAL,
2956                                 true /*isResponse*/,
2957                                 ikeMessage.ikeHeader.messageId);
2958 
2959                 sendEncryptedIkeMessage(mCurrentIkeSaRecord, msg);
2960                 return;
2961             }
2962 
2963             // Normal path
2964             List<IkePayload> payloads = new LinkedList<>();
2965             payloads.addAll(ikeMessage.ikePayloadList);
2966             payloads.removeAll(handledPayloads);
2967 
2968             mAwaitingChildResponse.add(targetChild);
2969             mChildInRemoteProcedures.add(targetChild);
2970 
2971             targetChild.receiveRequest(
2972                     IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, ikeMessage.ikeHeader.exchangeType, payloads);
2973         }
2974 
handleOutboundRequest(int exchangeType, List<IkePayload> outboundPayloads)2975         private void handleOutboundRequest(int exchangeType, List<IkePayload> outboundPayloads) {
2976             IkeHeader ikeHeader =
2977                     new IkeHeader(
2978                             mCurrentIkeSaRecord.getInitiatorSpi(),
2979                             mCurrentIkeSaRecord.getResponderSpi(),
2980                             IkePayload.PAYLOAD_TYPE_SK,
2981                             exchangeType,
2982                             false /*isResp*/,
2983                             mCurrentIkeSaRecord.isLocalInit,
2984                             mCurrentIkeSaRecord.getLocalRequestMessageId());
2985             IkeMessage ikeMessage = new IkeMessage(ikeHeader, outboundPayloads);
2986 
2987             mRetransmitter = new EncryptedRetransmitter(ikeMessage);
2988         }
2989 
handleOutboundResponse( int exchangeType, List<IkePayload> outboundPayloads, ChildSessionStateMachine childSession)2990         private void handleOutboundResponse(
2991                 int exchangeType,
2992                 List<IkePayload> outboundPayloads,
2993                 ChildSessionStateMachine childSession) {
2994             // For each request IKE passed to Child, Child will send back to IKE a response. Even
2995             // if the Child Session is under simultaneous deletion, it will send back an empty
2996             // payload list.
2997             mOutboundRespPayloads.addAll(outboundPayloads);
2998             mAwaitingChildResponse.remove(childSession);
2999 
3000             // When the server tries to delete multiple Child Sessions in one IKE exchange,
3001             // mAwaitingChildResponse may not be empty. It means that there are Child Sessions
3002             // have not sent IKE Session the delete responses. In this case IKE Session needs to
3003             // return and keep waiting for all the Child responses in this state.
3004             if (!mAwaitingChildResponse.isEmpty()) return;
3005 
3006             IkeHeader ikeHeader =
3007                     new IkeHeader(
3008                             mCurrentIkeSaRecord.getInitiatorSpi(),
3009                             mCurrentIkeSaRecord.getResponderSpi(),
3010                             IkePayload.PAYLOAD_TYPE_SK,
3011                             exchangeType,
3012                             true /*isResp*/,
3013                             mCurrentIkeSaRecord.isLocalInit,
3014                             mLastInboundRequestMsgId);
3015             IkeMessage ikeMessage = new IkeMessage(ikeHeader, mOutboundRespPayloads);
3016             sendEncryptedIkeMessage(ikeMessage);
3017 
3018             // Clear mOutboundRespPayloads so that in a two-exchange process (e.g. Rekey Child), the
3019             // response of the first exchange won't be added to the response of the second exchange.
3020             mOutboundRespPayloads.clear();
3021         }
3022     }
3023 
3024     /** CreateIkeLocalIkeInit represents state when IKE library initiates IKE_INIT exchange. */
3025     @VisibleForTesting
3026     public class CreateIkeLocalIkeInit extends BusyState {
3027         private InitialSetupData mInitialSetupData;
3028         private byte[] mIkeInitRequestBytes;
3029         private byte[] mIkeInitResponseBytes;
3030         private IkeNoncePayload mIkeInitNoncePayload;
3031         private IkeNoncePayload mIkeRespNoncePayload;
3032         private Set<Short> mPeerSignatureHashAlgorithms = new HashSet<>();
3033 
3034         private IkeSecurityParameterIndex mLocalIkeSpiResource;
3035         private IkeSecurityParameterIndex mRemoteIkeSpiResource;
3036         private Retransmitter mRetransmitter;
3037 
3038         // TODO: Support negotiating IKE fragmentation
3039 
3040         @Override
enterState()3041         public void enterState() {
3042             if (mInitialSetupData == null) {
3043                 handleIkeFatalError(
3044                         wrapAsIkeException(new IllegalStateException("mInitialSetupData is null")));
3045                 return;
3046             }
3047 
3048             try {
3049                 sendRequest(buildIkeInitReq());
3050             } catch (IOException e) {
3051                 // Fail to assign IKE SPI
3052                 handleIkeFatalError(e);
3053             }
3054         }
3055 
sendRequest(IkeMessage request)3056         private void sendRequest(IkeMessage request) {
3057             // Register local SPI to receive the IKE INIT response.
3058             mIkeConnectionCtrl.registerIkeSpi(request.ikeHeader.ikeInitiatorSpi);
3059 
3060             mIkeInitRequestBytes = request.encode();
3061             mIkeInitNoncePayload =
3062                     request.getPayloadForType(IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class);
3063 
3064             if (mRetransmitter != null) {
3065                 mRetransmitter.stopRetransmitting();
3066             }
3067             mRetransmitter = new UnencryptedRetransmitter(request);
3068         }
3069 
3070         @Override
triggerRetransmit()3071         protected void triggerRetransmit() {
3072             mRetransmitter.retransmit();
3073         }
3074 
setIkeSetupData(InitialSetupData setupData)3075         public void setIkeSetupData(InitialSetupData setupData) {
3076             mInitialSetupData = setupData;
3077         }
3078 
3079         @Override
processStateMessage(Message message)3080         public boolean processStateMessage(Message message) {
3081             switch (message.what) {
3082                 case CMD_RECEIVE_IKE_PACKET:
3083                     handleReceivedIkePacket(message);
3084                     return HANDLED;
3085 
3086                 case CMD_SET_NETWORK:
3087                     // Shouldn't be receiving this command before MOBIKE is active - determined with
3088                     // last IKE_AUTH response
3089                     logWtf("Received SET_NETWORK cmd in " + getCurrentStateName());
3090                     return NOT_HANDLED;
3091 
3092                 default:
3093                     return super.processStateMessage(message);
3094             }
3095         }
3096 
handleReceivedIkePacket(Message message)3097         protected void handleReceivedIkePacket(Message message) {
3098             String methodTag = "handleReceivedIkePacket: ";
3099 
3100             ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
3101             IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
3102             byte[] ikePacketBytes = receivedIkePacket.ikePacketBytes;
3103 
3104             logd(
3105                     methodTag
3106                             + "Received an "
3107                             + ikeHeader.getBasicInfoString()
3108                             + ". Packet size: "
3109                             + ikePacketBytes.length);
3110 
3111             if (ikeHeader.isResponseMsg) {
3112                 DecodeResult decodeResult = IkeMessage.decode(0, ikeHeader, ikePacketBytes);
3113 
3114                 switch (decodeResult.status) {
3115                     case DECODE_STATUS_OK:
3116                         mIkeInitResponseBytes = ikePacketBytes;
3117                         handleResponseIkeMessage(((DecodeResultOk) decodeResult).ikeMessage);
3118 
3119                         // SA negotiation failed
3120                         if (mCurrentIkeSaRecord == null) break;
3121 
3122                         mCurrentIkeSaRecord.incrementLocalRequestMessageId();
3123                         break;
3124                     case DECODE_STATUS_PARTIAL:
3125                         // Fall through. We don't support IKE fragmentation here. We should never
3126                         // get this status.
3127                     case DECODE_STATUS_PROTECTED_ERROR:
3128                         // IKE INIT response is not protected. So we should never get this status
3129                         cleanUpAndQuit(
3130                                 new IllegalStateException(
3131                                         "Unexpected decoding status: " + decodeResult.status));
3132                         break;
3133                     case DECODE_STATUS_UNPROTECTED_ERROR:
3134                         logi(
3135                                 "Discard unencrypted response with syntax error",
3136                                 ((DecodeResultError) decodeResult).ikeException);
3137                         break;
3138                     default:
3139                         cleanUpAndQuit(
3140                                 new IllegalStateException(
3141                                         "Invalid decoding status: " + decodeResult.status));
3142                 }
3143 
3144             } else {
3145                 // TODO: Also prettyprint IKE header in the log.
3146                 logi("Received a request while waiting for IKE_INIT response. Discard it.");
3147             }
3148         }
3149 
3150         /** Returns the Notify-Cookie payload, or null if it does not exist */
getNotifyCookie(IkeMessage ikeMessage)3151         private IkeNotifyPayload getNotifyCookie(IkeMessage ikeMessage) {
3152             List<IkeNotifyPayload> notifyPayloads =
3153                     ikeMessage.getPayloadListForType(PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
3154             for (IkeNotifyPayload notify : notifyPayloads) {
3155                 if (notify.notifyType == NOTIFY_TYPE_COOKIE) {
3156                     return notify;
3157                 }
3158             }
3159             return null;
3160         }
3161 
3162         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)3163         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
3164             // IKE_SA_INIT exchange and IKE SA setup succeed
3165             boolean ikeInitSuccess = false;
3166 
3167             // IKE INIT is not finished. IKE_SA_INIT request was re-sent with Notify-Cookie,
3168             // and the same INIT SPI and other payloads.
3169             boolean ikeInitRetriedWithCookie = false;
3170 
3171             try {
3172                 int exchangeType = ikeMessage.ikeHeader.exchangeType;
3173                 if (exchangeType != IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT) {
3174                     throw new InvalidSyntaxException(
3175                             "Expected EXCHANGE_TYPE_IKE_SA_INIT but received: " + exchangeType);
3176                 }
3177 
3178                 // Retry IKE INIT if there is Notify-Cookie
3179                 IkeNotifyPayload inCookiePayload = getNotifyCookie(ikeMessage);
3180                 if (inCookiePayload != null) {
3181                     IkeNotifyPayload outCookiePayload =
3182                             IkeNotifyPayload.handleCookieAndGenerateCopy(inCookiePayload);
3183                     IkeMessage initReq =
3184                             buildReqWithCookie(mRetransmitter.getMessage(), outCookiePayload);
3185 
3186                     sendRequest(initReq);
3187                     ikeInitRetriedWithCookie = true;
3188                     return;
3189                 }
3190 
3191                 // Negotiate IKE SA
3192                 validateIkeInitResp(mRetransmitter.getMessage(), ikeMessage);
3193 
3194                 mCurrentIkeSaRecord =
3195                         IkeSaRecord.makeFirstIkeSaRecord(
3196                                 mRetransmitter.getMessage(),
3197                                 ikeMessage,
3198                                 mLocalIkeSpiResource,
3199                                 mRemoteIkeSpiResource,
3200                                 mIkePrf,
3201                                 mIkeIntegrity == null ? 0 : mIkeIntegrity.getKeyLength(),
3202                                 mIkeCipher.getKeyLength(),
3203                                 buildSaLifetimeAlarmScheduler(mRemoteIkeSpiResource.getSpi()));
3204 
3205                 addIkeSaRecord(mCurrentIkeSaRecord);
3206                 ikeInitSuccess = true;
3207 
3208                 mCreateIkeLocalIkeAuth.setIkeSetupData(
3209                         new IkeInitData(
3210                                 mInitialSetupData,
3211                                 mIkeInitRequestBytes,
3212                                 mIkeInitResponseBytes,
3213                                 mIkeInitNoncePayload,
3214                                 mIkeRespNoncePayload,
3215                                 mPeerSignatureHashAlgorithms));
3216                 transitionTo(mCreateIkeLocalIkeAuth);
3217             } catch (IkeProtocolException | GeneralSecurityException | IOException e) {
3218                 if (e instanceof InvalidKeException) {
3219                     InvalidKeException keException = (InvalidKeException) e;
3220 
3221                     int requestedDhGroup = keException.getDhGroup();
3222                     boolean doAllProposalsHaveDhGroup = true;
3223                     for (IkeSaProposal proposal : mIkeSessionParams.getSaProposalsInternal()) {
3224                         doAllProposalsHaveDhGroup &=
3225                                 proposal.getDhGroups().contains(requestedDhGroup);
3226                     }
3227 
3228                     // If DH group is not acceptable for all proposals, fail. The caller explicitly
3229                     // did not want that combination, and the IKE library must honor it.
3230                     if (doAllProposalsHaveDhGroup) {
3231                         // Remove state set during request creation
3232                         mIkeConnectionCtrl.unregisterIkeSpi(
3233                                 mRetransmitter.getMessage().ikeHeader.ikeInitiatorSpi);
3234                         mIkeInitRequestBytes = null;
3235                         mIkeInitNoncePayload = null;
3236 
3237                         mInitial.setIkeSetupData(
3238                                 new InitialSetupData(
3239                                         mInitialSetupData.firstChildSessionParams,
3240                                         mInitialSetupData.firstChildCallback,
3241                                         requestedDhGroup));
3242                         transitionTo(mInitial);
3243                         openSession();
3244 
3245                         return;
3246                     }
3247                 }
3248 
3249                 handleIkeFatalError(e);
3250             } finally {
3251                 if (!ikeInitSuccess && !ikeInitRetriedWithCookie) {
3252                     if (mLocalIkeSpiResource != null) {
3253                         mLocalIkeSpiResource.close();
3254                         mLocalIkeSpiResource = null;
3255                     }
3256                     if (mRemoteIkeSpiResource != null) {
3257                         mRemoteIkeSpiResource.close();
3258                         mRemoteIkeSpiResource = null;
3259                     }
3260                 }
3261             }
3262         }
3263 
buildIkeInitReq()3264         private IkeMessage buildIkeInitReq() throws IOException {
3265             // Generate IKE SPI
3266             mLocalIkeSpiResource =
3267                     mIkeSpiGenerator.allocateSpi(mIkeConnectionCtrl.getLocalAddress());
3268 
3269             long initSpi = mLocalIkeSpiResource.getSpi();
3270             long respSpi = 0;
3271 
3272             // It is validated in IkeSessionParams.Builder to ensure IkeSessionParams has at least
3273             // one IkeSaProposal and all SaProposals are valid for IKE SA negotiation.
3274             IkeSaProposal[] saProposals = mIkeSessionParams.getSaProposalsInternal();
3275             List<IkePayload> payloadList =
3276                     CreateIkeSaHelper.getIkeInitSaRequestPayloads(
3277                             saProposals,
3278                             mInitialSetupData.peerSelectedDhGroup,
3279                             initSpi,
3280                             respSpi,
3281                             mIkeConnectionCtrl.getLocalAddress(),
3282                             mIkeConnectionCtrl.getRemoteAddress(),
3283                             mIkeConnectionCtrl.getLocalPort(),
3284                             mIkeConnectionCtrl.getRemotePort(),
3285                             mIkeContext.getRandomnessFactory(),
3286                             needEnableForceUdpEncap());
3287             payloadList.add(
3288                     new IkeNotifyPayload(
3289                             IkeNotifyPayload.NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED));
3290 
3291             ByteBuffer signatureHashAlgoTypes =
3292                     ByteBuffer.allocate(
3293                             IkeAuthDigitalSignPayload.ALL_SIGNATURE_ALGO_TYPES.length * 2);
3294             for (short type : IkeAuthDigitalSignPayload.ALL_SIGNATURE_ALGO_TYPES) {
3295                 signatureHashAlgoTypes.putShort(type);
3296             }
3297             payloadList.add(
3298                     new IkeNotifyPayload(
3299                             IkeNotifyPayload.NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS,
3300                             signatureHashAlgoTypes.array()));
3301 
3302             // TODO: Add Notification Payloads according to user configurations.
3303 
3304             // Build IKE header
3305             IkeHeader ikeHeader =
3306                     new IkeHeader(
3307                             initSpi,
3308                             respSpi,
3309                             IkePayload.PAYLOAD_TYPE_SA,
3310                             IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT,
3311                             false /*isResponseMsg*/,
3312                             true /*fromIkeInitiator*/,
3313                             0 /*messageId*/);
3314 
3315             return new IkeMessage(ikeHeader, payloadList);
3316         }
3317 
3318         /**
3319          * Builds an IKE INIT request that has the same payloads and SPI with the original request,
3320          * and with the new Notify-Cookie Payload as the first payload.
3321          */
buildReqWithCookie( IkeMessage originalReq, IkeNotifyPayload cookieNotify)3322         private IkeMessage buildReqWithCookie(
3323                 IkeMessage originalReq, IkeNotifyPayload cookieNotify) {
3324             List<IkePayload> payloads = new ArrayList<>();
3325 
3326             // Notify-Cookie MUST be the first payload.
3327             payloads.add(cookieNotify);
3328 
3329             for (IkePayload payload : originalReq.ikePayloadList) {
3330                 // Keep all previous payloads except COOKIEs
3331                 if (payload instanceof IkeNotifyPayload
3332                         && ((IkeNotifyPayload) payload).notifyType == NOTIFY_TYPE_COOKIE) {
3333                     continue;
3334                 }
3335                 payloads.add(payload);
3336             }
3337 
3338             IkeHeader originalHeader = originalReq.ikeHeader;
3339             IkeHeader header =
3340                     new IkeHeader(
3341                             originalHeader.ikeInitiatorSpi,
3342                             originalHeader.ikeResponderSpi,
3343                             PAYLOAD_TYPE_NOTIFY,
3344                             IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT,
3345                             false /* isResponseMsg */,
3346                             true /* fromIkeInitiator */,
3347                             0 /* messageId */);
3348             return new IkeMessage(header, payloads);
3349         }
3350 
validateIkeInitResp(IkeMessage reqMsg, IkeMessage respMsg)3351         private void validateIkeInitResp(IkeMessage reqMsg, IkeMessage respMsg)
3352                 throws IkeProtocolException, IOException {
3353             IkeHeader respIkeHeader = respMsg.ikeHeader;
3354             mRemoteIkeSpiResource =
3355                     mIkeSpiGenerator.allocateSpi(
3356                             mIkeConnectionCtrl.getRemoteAddress(), respIkeHeader.ikeResponderSpi);
3357 
3358             IkeSaPayload respSaPayload = null;
3359             IkeKePayload respKePayload = null;
3360 
3361             /**
3362              * There MAY be multiple NAT_DETECTION_SOURCE_IP payloads in a message if the sender
3363              * does not know which of several network attachments will be used to send the packet.
3364              */
3365             List<IkeNotifyPayload> natSourcePayloads = new LinkedList<>();
3366             IkeNotifyPayload natDestPayload = null;
3367 
3368             boolean hasNoncePayload = false;
3369 
3370             for (IkePayload payload : respMsg.ikePayloadList) {
3371                 switch (payload.payloadType) {
3372                     case IkePayload.PAYLOAD_TYPE_SA:
3373                         respSaPayload = (IkeSaPayload) payload;
3374                         break;
3375                     case IkePayload.PAYLOAD_TYPE_KE:
3376                         respKePayload = (IkeKePayload) payload;
3377                         break;
3378                     case IkePayload.PAYLOAD_TYPE_CERT_REQUEST:
3379                         // Certificates unconditionally sent (only) for Digital Signature Auth
3380                         break;
3381                     case IkePayload.PAYLOAD_TYPE_NONCE:
3382                         hasNoncePayload = true;
3383                         mIkeRespNoncePayload = (IkeNoncePayload) payload;
3384                         break;
3385                     case IkePayload.PAYLOAD_TYPE_VENDOR:
3386                         mRemoteVendorIds.add(((IkeVendorPayload) payload).vendorId);
3387                         break;
3388                     case IkePayload.PAYLOAD_TYPE_NOTIFY:
3389                         IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
3390 
3391                         if (notifyPayload.isErrorNotify()) {
3392                             throw notifyPayload.validateAndBuildIkeException();
3393                         }
3394 
3395                         switch (notifyPayload.notifyType) {
3396                             case NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP:
3397                                 natSourcePayloads.add(notifyPayload);
3398                                 break;
3399                             case NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP:
3400                                 if (natDestPayload != null) {
3401                                     throw new InvalidSyntaxException(
3402                                             "More than one"
3403                                                     + " NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP"
3404                                                     + " found");
3405                                 }
3406                                 natDestPayload = notifyPayload;
3407                                 break;
3408                             case NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED:
3409                                 mEnabledExtensions.add(EXTENSION_TYPE_FRAGMENTATION);
3410                                 break;
3411                             case NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS:
3412                                 mPeerSignatureHashAlgorithms.addAll(
3413                                         IkeAuthDigitalSignPayload
3414                                                 .getSignatureHashAlgorithmsFromIkeNotifyPayload(
3415                                                         notifyPayload));
3416                                 break;
3417                             default:
3418                                 // Unknown and unexpected status notifications are ignored as per
3419                                 // RFC7296.
3420                                 logw(
3421                                         "Received unknown or unexpected status notifications with"
3422                                                 + " notify type: "
3423                                                 + notifyPayload.notifyType);
3424                         }
3425 
3426                         break;
3427                     default:
3428                         logw(
3429                                 "Received unexpected payload in IKE INIT response. Payload type: "
3430                                         + payload.payloadType);
3431                 }
3432             }
3433 
3434             if (respSaPayload == null
3435                     || respKePayload == null
3436                     || !hasNoncePayload) {
3437                 throw new InvalidSyntaxException("SA, KE, or Nonce payload missing.");
3438             }
3439 
3440             IkeSaPayload reqSaPayload =
3441                     reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
3442             mSaProposal =
3443                     IkeSaPayload.getVerifiedNegotiatedIkeProposalPair(
3444                                     reqSaPayload,
3445                                     respSaPayload,
3446                                     mIkeSpiGenerator,
3447                                     mIkeConnectionCtrl.getRemoteAddress())
3448                             .second
3449                             .saProposal;
3450 
3451             // Build IKE crypto tools using mSaProposal. It is ensured that mSaProposal is valid and
3452             // has exactly one Transform for each Transform type. Only exception is when
3453             // combined-mode cipher is used, there will be either no integrity algorithm or an
3454             // INTEGRITY_ALGORITHM_NONE type algorithm.
3455             mIkeCipher = IkeCipher.create(mSaProposal.getEncryptionTransforms()[0]);
3456             if (!mIkeCipher.isAead()) {
3457                 mIkeIntegrity = IkeMacIntegrity.create(mSaProposal.getIntegrityTransforms()[0]);
3458             }
3459             mIkePrf = IkeMacPrf.create(mSaProposal.getPrfTransforms()[0]);
3460 
3461             IkeKePayload reqKePayload =
3462                     reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
3463             if (reqKePayload.dhGroup != respKePayload.dhGroup
3464                     && respKePayload.dhGroup != mInitialSetupData.peerSelectedDhGroup) {
3465                 throw new InvalidSyntaxException("Received KE payload with mismatched DH group.");
3466             }
3467 
3468             if (reqMsg.hasNotifyPayload(NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP)) {
3469                 handleNatDetection(respMsg, natSourcePayloads, natDestPayload);
3470             }
3471         }
3472 
handleNatDetection( IkeMessage respMsg, List<IkeNotifyPayload> natSourcePayloads, IkeNotifyPayload natDestPayload)3473         private void handleNatDetection(
3474                 IkeMessage respMsg,
3475                 List<IkeNotifyPayload> natSourcePayloads,
3476                 IkeNotifyPayload natDestPayload)
3477                 throws InvalidSyntaxException, IOException {
3478             if (!didPeerIncludeNattDetectionPayloads(natSourcePayloads, natDestPayload)) {
3479                 mIkeConnectionCtrl.markSeverNattUnsupported();
3480                 return;
3481             }
3482 
3483             // NAT detection
3484             long initIkeSpi = respMsg.ikeHeader.ikeInitiatorSpi;
3485             long respIkeSpi = respMsg.ikeHeader.ikeResponderSpi;
3486             boolean isNatDetected =
3487                     isLocalOrRemoteNatDetected(
3488                             initIkeSpi, respIkeSpi, natSourcePayloads, natDestPayload);
3489 
3490             try {
3491                 mIkeConnectionCtrl.handleNatDetectionResultInIkeInit(isNatDetected, initIkeSpi);
3492             } catch (IkeException e) {
3493                 handleIkeFatalError(e);
3494             }
3495         }
3496 
3497         @Override
exitState()3498         public void exitState() {
3499             super.exitState();
3500 
3501             mInitialSetupData = null;
3502             if (mRetransmitter != null) {
3503                 mRetransmitter.stopRetransmitting();
3504             }
3505         }
3506 
3507         private class UnencryptedRetransmitter extends Retransmitter {
3508             private final byte[] mIkePacket;
3509 
UnencryptedRetransmitter(IkeMessage msg)3510             private UnencryptedRetransmitter(IkeMessage msg) {
3511                 super(getHandler(), msg, mIkeSessionParams.getRetransmissionTimeoutsMillis());
3512                 mIkePacket = msg.encode();
3513                 retransmit();
3514             }
3515 
3516             @Override
send()3517             public void send() {
3518                 // Sends unencrypted packet
3519                 mIkeConnectionCtrl.sendIkePacket(mIkePacket);
3520             }
3521 
3522             @Override
handleRetransmissionFailure()3523             public void handleRetransmissionFailure() {
3524                 handleIkeFatalError(
3525                         ShimUtils.getInstance()
3526                                 .getRetransmissionFailedException(
3527                                         "Retransmitting IKE INIT request failure"));
3528             }
3529         }
3530     }
3531 
3532     /**
3533      * Returns if the peer included NAT-T detection payloads
3534      *
3535      * @throws InvalidSyntaxException if an invalid combination of NAT-T detection payloads are
3536      *     received.
3537      */
didPeerIncludeNattDetectionPayloads( List<IkeNotifyPayload> natSourcePayloads, IkeNotifyPayload natDestPayload)3538     private boolean didPeerIncludeNattDetectionPayloads(
3539             List<IkeNotifyPayload> natSourcePayloads, IkeNotifyPayload natDestPayload)
3540             throws InvalidSyntaxException {
3541         if (!natSourcePayloads.isEmpty() && natDestPayload != null) {
3542             return true;
3543         } else if (natSourcePayloads.isEmpty() && natDestPayload == null) {
3544             return false;
3545         } else {
3546             throw new InvalidSyntaxException(
3547                     "Missing source or destination NAT detection notification");
3548         }
3549     }
3550 
3551     /** Returns whether the local or remote peer is a behind NAT. */
isLocalOrRemoteNatDetected( long initIkeSpi, long respIkeSpi, List<IkeNotifyPayload> natSourcePayloads, IkeNotifyPayload natDestPayload)3552     private boolean isLocalOrRemoteNatDetected(
3553             long initIkeSpi,
3554             long respIkeSpi,
3555             List<IkeNotifyPayload> natSourcePayloads,
3556             IkeNotifyPayload natDestPayload) {
3557         // Check if local node is behind NAT
3558         byte[] expectedLocalNatData =
3559                 IkeNotifyPayload.generateNatDetectionData(
3560                         initIkeSpi,
3561                         respIkeSpi,
3562                         mIkeConnectionCtrl.getLocalAddress(),
3563                         mIkeConnectionCtrl.getLocalPort());
3564         boolean localNatDetected = !Arrays.equals(expectedLocalNatData, natDestPayload.notifyData);
3565 
3566         // Check if the remote node is behind NAT
3567         byte[] expectedRemoteNatData =
3568                 IkeNotifyPayload.generateNatDetectionData(
3569                         initIkeSpi,
3570                         respIkeSpi,
3571                         mIkeConnectionCtrl.getRemoteAddress(),
3572                         mIkeConnectionCtrl.getRemotePort());
3573         boolean remoteNatDetected = true;
3574         for (IkeNotifyPayload natPayload : natSourcePayloads) {
3575             // If none of the received hash matches the expected value, the remote node is
3576             // behind NAT.
3577             if (Arrays.equals(expectedRemoteNatData, natPayload.notifyData)) {
3578                 remoteNatDetected = false;
3579             }
3580         }
3581 
3582         if (!localNatDetected && needEnableForceUdpEncap()) {
3583             logd("there is no actual local NAT, but we have faked it");
3584             localNatDetected = true;
3585         }
3586 
3587         return localNatDetected || remoteNatDetected;
3588     }
3589 
3590     /**
3591      * MsgValidationResult represents a validation result of an inbound IKE message.
3592      *
3593      * <p>An inbound IKE message might need to go through multiple stages of validations. Thus
3594      * RESULT_OK only represents the success of the current validation stage. It does not mean the
3595      * message is fully validated.
3596      */
3597     private static class MsgValidationResult {
3598         /** The validation succeeds. */
3599         static final int RESULT_OK = 0;
3600         /** The inbound message is invalid. */
3601         static final int RESULT_ERROR_INVALID_MESSAGE = 1;
3602         /** The inbound message includes error notification that will fail the exchange. */
3603         static final int RESULT_ERROR_RCV_NOTIFY = 2;
3604 
3605         private final int mResult;
3606         @Nullable private final IkeException mException;
3607 
MsgValidationResult(int result, @Nullable IkeException exception)3608         private MsgValidationResult(int result, @Nullable IkeException exception) {
3609             mResult = result;
3610             mException = exception;
3611         }
3612 
newResultOk()3613         static MsgValidationResult newResultOk() {
3614             return new MsgValidationResult(RESULT_OK, null);
3615         }
3616 
newResultInvalidMsg(@onNull IkeException exception)3617         static MsgValidationResult newResultInvalidMsg(@NonNull IkeException exception) {
3618             return new MsgValidationResult(RESULT_ERROR_INVALID_MESSAGE, exception);
3619         }
3620 
newResultRcvErrorNotify( @onNull IkeProtocolException exception)3621         static MsgValidationResult newResultRcvErrorNotify(
3622                 @NonNull IkeProtocolException exception) {
3623             return new MsgValidationResult(RESULT_ERROR_RCV_NOTIFY, exception);
3624         }
3625 
getResult()3626         int getResult() {
3627             return mResult;
3628         }
3629 
3630         @Nullable
getException()3631         IkeException getException() {
3632             return mException;
3633         }
3634     }
3635 
3636     /**
3637      * CreateIkeLocalIkeAuthBase represents the common state and functionality required to perform
3638      * IKE AUTH exchanges in both the EAP and non-EAP flows.
3639      */
3640     abstract class CreateIkeLocalIkeAuthBase<T extends IkeInitData> extends DeleteBase {
3641         protected T mSetupData;
3642         protected Retransmitter mRetransmitter;
3643         protected EapInfo mEapInfo = null;
3644 
3645         @Override
enterState()3646         public void enterState() {
3647             if (mSetupData == null) {
3648                 handleIkeFatalError(
3649                         wrapAsIkeException(new IllegalStateException("mSetupData is null")));
3650                 return;
3651             }
3652         }
3653 
setIkeSetupData(T setupData)3654         public void setIkeSetupData(T setupData) {
3655             mSetupData = setupData;
3656         }
3657 
setEapInfo(EapInfo eapInfo)3658         protected void setEapInfo(EapInfo eapInfo) {
3659             mEapInfo = eapInfo;
3660         }
3661 
3662         @Override
triggerRetransmit()3663         protected void triggerRetransmit() {
3664             mRetransmitter.retransmit();
3665         }
3666 
3667         @Override
exitState()3668         public void exitState() {
3669             mSetupData = null;
3670 
3671             if (mRetransmitter != null) {
3672                 mRetransmitter.stopRetransmitting();
3673             }
3674         }
3675 
3676         // TODO: b/139482382 If receiving a remote request while waiting for the last IKE AUTH
3677         // response, defer it to next state.
3678 
3679         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)3680         protected void handleRequestIkeMessage(
3681                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
3682             IkeSaRecord ikeSaRecord = getIkeSaRecordForPacket(ikeMessage.ikeHeader);
3683 
3684             // Null out last received packet, so the next state (that handles the actual request)
3685             // does not treat the message as a retransmission.
3686             ikeSaRecord.updateLastReceivedReqFirstPacket(null);
3687 
3688             // Send to next state; we can't handle this yet.
3689             deferMessage(message);
3690         }
3691 
buildIkeAuthReqMessage(List<IkePayload> payloadList)3692         protected IkeMessage buildIkeAuthReqMessage(List<IkePayload> payloadList) {
3693             // Build IKE header
3694             IkeHeader ikeHeader =
3695                     new IkeHeader(
3696                             mCurrentIkeSaRecord.getInitiatorSpi(),
3697                             mCurrentIkeSaRecord.getResponderSpi(),
3698                             IkePayload.PAYLOAD_TYPE_SK,
3699                             IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
3700                             false /*isResponseMsg*/,
3701                             true /*fromIkeInitiator*/,
3702                             mCurrentIkeSaRecord.getLocalRequestMessageId());
3703 
3704             return new IkeMessage(ikeHeader, payloadList);
3705         }
3706     }
3707 
3708     /**
3709      * CreateIkeLocalIkeAuthFirstAndLastExchangeBase represents the common states and
3710      * functionalities required to perform the first and the last IKE AUTH exchanges.
3711      */
3712     abstract class CreateIkeLocalIkeAuthFirstAndLastExchangeBase<T extends IkeInitData>
3713             extends CreateIkeLocalIkeAuthBase<T> {
authenticatePsk( byte[] psk, IkeAuthPayload authPayload, IkeIdPayload respIdPayload)3714         protected void authenticatePsk(
3715                 byte[] psk, IkeAuthPayload authPayload, IkeIdPayload respIdPayload)
3716                 throws AuthenticationFailedException {
3717             if (authPayload.authMethod != IkeAuthPayload.AUTH_METHOD_PRE_SHARED_KEY) {
3718                 throw new AuthenticationFailedException(
3719                         "Expected the remote/server to use PSK-based authentication but"
3720                                 + " they used: "
3721                                 + authPayload.authMethod);
3722             }
3723 
3724             IkeAuthPskPayload pskPayload = (IkeAuthPskPayload) authPayload;
3725             pskPayload.verifyInboundSignature(
3726                     psk,
3727                     mSetupData.ikeInitResponseBytes,
3728                     mCurrentIkeSaRecord.nonceInitiator,
3729                     respIdPayload.getEncodedPayloadBody(),
3730                     mIkePrf,
3731                     mCurrentIkeSaRecord.getSkPr());
3732         }
3733 
extractChildPayloadsFromMessage(IkeMessage ikeMessage)3734         protected List<IkePayload> extractChildPayloadsFromMessage(IkeMessage ikeMessage) {
3735             List<IkePayload> list = new LinkedList<>();
3736             for (IkePayload payload : ikeMessage.ikePayloadList) {
3737                 switch (payload.payloadType) {
3738                     case PAYLOAD_TYPE_SA: // fall through
3739                     case PAYLOAD_TYPE_TS_INITIATOR: // fall through
3740                     case PAYLOAD_TYPE_TS_RESPONDER: // fall through
3741                     case PAYLOAD_TYPE_CP:
3742                         list.add(payload);
3743                         break;
3744                     case PAYLOAD_TYPE_NOTIFY:
3745                         if (((IkeNotifyPayload) payload).isNewChildSaNotify()) {
3746                             list.add(payload);
3747                         }
3748                         break;
3749                     default:
3750                         // Ignore payloads unrelated with Child negotiation
3751                 }
3752             }
3753 
3754             // Payload validation is done in ChildSessionStateMachine
3755             return list;
3756         }
3757 
performFirstChildNegotiation( List<IkePayload> childReqList, List<IkePayload> childRespList)3758         protected void performFirstChildNegotiation(
3759                 List<IkePayload> childReqList, List<IkePayload> childRespList) {
3760             childReqList.add(mSetupData.ikeInitNoncePayload);
3761             childRespList.add(mSetupData.ikeRespNoncePayload);
3762 
3763             deferMessage(
3764                     obtainMessage(
3765                             CMD_HANDLE_FIRST_CHILD_NEGOTIATION,
3766                             new FirstChildNegotiationData(
3767                                     mSetupData.firstChildSessionParams,
3768                                     mSetupData.firstChildCallback,
3769                                     childReqList,
3770                                     childRespList)));
3771 
3772             transitionTo(mChildProcedureOngoing);
3773         }
3774 
buildIkeSessionConfiguration(IkeMessage ikeMessage)3775         protected IkeSessionConfiguration buildIkeSessionConfiguration(IkeMessage ikeMessage) {
3776             IkeConfigPayload configPayload =
3777                     ikeMessage.getPayloadForType(
3778                             IkePayload.PAYLOAD_TYPE_CP, IkeConfigPayload.class);
3779             if (configPayload == null) {
3780                 logi("No config payload in ikeMessage.");
3781             } else if (configPayload.configType != CONFIG_TYPE_REPLY) {
3782                 logi("Unexpected config payload. Config Type: " + configPayload.configType);
3783                 configPayload = null;
3784             }
3785 
3786             return new IkeSessionConfiguration(
3787                     mIkeConnectionCtrl.buildIkeSessionConnectionInfo(),
3788                     configPayload,
3789                     mRemoteVendorIds,
3790                     mEnabledExtensions,
3791                     mEapInfo);
3792         }
3793 
notifyIkeSessionSetup(IkeMessage msg)3794         protected void notifyIkeSessionSetup(IkeMessage msg) {
3795             IkeSessionConfiguration ikeSessionConfig = buildIkeSessionConfiguration(msg);
3796             executeUserCallback(
3797                     () -> {
3798                         mIkeSessionCallback.onOpened(ikeSessionConfig);
3799                     });
3800         }
3801 
handleNotifyInLastAuthResp( IkeNotifyPayload notifyPayload, IkeAuthPayload authPayload)3802         protected MsgValidationResult handleNotifyInLastAuthResp(
3803                 IkeNotifyPayload notifyPayload, IkeAuthPayload authPayload) {
3804             if (notifyPayload.isErrorNotify()) {
3805                 if (notifyPayload.isNewChildSaNotify() && authPayload != null) {
3806                     // If error is for creating Child and Auth payload is included, try
3807                     // to do authentication first and let ChildSessionStateMachine
3808                     // handle the error later.
3809                     return MsgValidationResult.newResultOk();
3810                 } else {
3811                     try {
3812                         return MsgValidationResult.newResultRcvErrorNotify(
3813                                 notifyPayload.validateAndBuildIkeException());
3814                     } catch (InvalidSyntaxException e) {
3815                         return MsgValidationResult.newResultInvalidMsg(e);
3816                     }
3817                 }
3818             } else if (notifyPayload.isNewChildSaNotify()) {
3819                 // If payload is not an error but is for the new Child, it's reasonable
3820                 // to receive here. Let the ChildSessionStateMachine handle it.
3821                 return MsgValidationResult.newResultOk();
3822             } else if (mIkeSessionParams.hasIkeOption(IKE_OPTION_MOBIKE)
3823                     && notifyPayload.notifyType == NOTIFY_TYPE_MOBIKE_SUPPORTED) {
3824                 logd("Both client and server support MOBIKE");
3825                 mEnabledExtensions.add(EXTENSION_TYPE_MOBIKE);
3826 
3827                 return MsgValidationResult.newResultOk();
3828             } else {
3829                 // Unknown and unexpected status notifications are ignored as per
3830                 // RFC7296.
3831                 logw(
3832                         "Received unknown or unexpected status notifications with"
3833                                 + " notify type: "
3834                                 + notifyPayload.notifyType);
3835                 return MsgValidationResult.newResultOk();
3836             }
3837         }
3838 
3839         /**
3840          * Validate the response, perform authentication and take next steps to finish IKE setup or
3841          * start EAP authentication.
3842          */
validateAuthRespAndTakeNextStep( IkeMessage ikeMessage)3843         protected abstract MsgValidationResult validateAuthRespAndTakeNextStep(
3844                 IkeMessage ikeMessage);
3845 
3846         /* Method to handle the first or the last IKE AUTH response */
handleIkeAuthResponse( IkeMessage ikeMessage, boolean isServerExpectingMoreEap)3847         protected void handleIkeAuthResponse(
3848                 IkeMessage ikeMessage, boolean isServerExpectingMoreEap) {
3849             int exchangeType = ikeMessage.ikeHeader.exchangeType;
3850             if (exchangeType != IkeHeader.EXCHANGE_TYPE_IKE_AUTH) {
3851                 sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
3852                 handleIkeFatalError(
3853                         new InvalidSyntaxException(
3854                                 "Expected EXCHANGE_TYPE_IKE_AUTH but received: " + exchangeType));
3855                 return;
3856             }
3857 
3858             final MsgValidationResult authRespResult = validateAuthRespAndTakeNextStep(ikeMessage);
3859 
3860             if (authRespResult.getResult() != MsgValidationResult.RESULT_OK) {
3861                 final IkeException e = authRespResult.getException();
3862                 if (!isServerExpectingMoreEap && !shouldSilentlyDelete(authRespResult)) {
3863                     // Notify the remote because they may have set up the IKE SA.
3864                     sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
3865                 }
3866                 handleIkeFatalError(authRespResult.getException());
3867             }
3868         }
3869 
3870         /**
3871          * Returns if this validation result indicates IKE termination without Delete exchange.
3872          *
3873          * <p>Receiving a fatal error notification in IKE AUTH should cause the IKE SA to be killed
3874          * without sending a Delete request.
3875          */
shouldSilentlyDelete(MsgValidationResult authRespResult)3876         protected boolean shouldSilentlyDelete(MsgValidationResult authRespResult) {
3877             if (authRespResult.getResult() != MsgValidationResult.RESULT_ERROR_RCV_NOTIFY) {
3878                 return false;
3879             }
3880 
3881             final IkeException e = authRespResult.getException();
3882             return (e instanceof InvalidSyntaxException
3883                     || e instanceof AuthenticationFailedException
3884                     || e instanceof UnsupportedCriticalPayloadException);
3885         }
3886 
maybeEnableMobility()3887         protected void maybeEnableMobility() throws IkeException {
3888             if (mEnabledExtensions.contains(EXTENSION_TYPE_MOBIKE)) {
3889                 logd("Enabling RFC4555 MOBIKE mobility");
3890                 mIkeConnectionCtrl.enableMobility();
3891                 return;
3892             } else if (mIkeSessionParams.hasIkeOption(IKE_OPTION_REKEY_MOBILITY)) {
3893                 logd(
3894                         "Enabling Rekey based mobility: IKE Session will try updating Child SA"
3895                                 + " addresses with Rekey");
3896                 mIkeConnectionCtrl.enableMobility();
3897                 return;
3898             } else {
3899                 logd(
3900                         "Mobility not enabled: IKE Session will not be able to handle network or"
3901                                 + " address changes");
3902             }
3903         }
3904     }
3905 
3906     /**
3907      * CreateIkeLocalIkeAuth represents state when IKE library initiates IKE_AUTH exchange.
3908      *
3909      * <p>If using EAP, CreateIkeLocalIkeAuth will transition to CreateIkeLocalIkeAuthInEap state
3910      * after validating the IKE AUTH response.
3911      */
3912     class CreateIkeLocalIkeAuth extends CreateIkeLocalIkeAuthFirstAndLastExchangeBase<IkeInitData> {
3913         private IkeIdPayload mInitIdPayload;
3914         private IkeIdPayload mRespIdPayload;
3915         private List<IkePayload> mFirstChildReqList;
3916         private boolean mUseEap;
3917 
3918         @Override
enterState()3919         public void enterState() {
3920             try {
3921                 super.enterState();
3922                 mRetransmitter = new EncryptedRetransmitter(buildIkeAuthReq());
3923                 mUseEap =
3924                         (IkeSessionParams.IKE_AUTH_METHOD_EAP
3925                                 == mIkeSessionParams.getLocalAuthConfig().mAuthMethod);
3926             } catch (SpiUnavailableException | ResourceUnavailableException e) {
3927                 // Handle IPsec SPI assigning failure.
3928                 handleIkeFatalError(e);
3929             }
3930         }
3931 
3932         @Override
processStateMessage(Message message)3933         public boolean processStateMessage(Message message) {
3934             switch (message.what) {
3935                 case CMD_SET_NETWORK:
3936                     // Shouldn't be receiving this command before MOBIKE is active - determined with
3937                     // last IKE_AUTH response
3938                     logWtf("Received SET_NETWORK cmd in " + getCurrentStateName());
3939                     return NOT_HANDLED;
3940 
3941                 default:
3942                     return super.processStateMessage(message);
3943             }
3944         }
3945 
3946         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)3947         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
3948             handleIkeAuthResponse(ikeMessage, mUseEap);
3949         }
3950 
3951         @Override
validateAuthRespAndTakeNextStep(IkeMessage ikeMessage)3952         public MsgValidationResult validateAuthRespAndTakeNextStep(IkeMessage ikeMessage) {
3953             MsgValidationResult validateResult = validateIkeAuthResp(ikeMessage);
3954             if (validateResult.getResult() != MsgValidationResult.RESULT_OK) {
3955                 return validateResult;
3956             }
3957 
3958             List<IkePayload> childReqList =
3959                     extractChildPayloadsFromMessage(mRetransmitter.getMessage());
3960             if (mUseEap) {
3961                 // childReqList needed after EAP completed, so persist to IkeSessionStateMachine
3962                 // state.
3963                 mFirstChildReqList = childReqList;
3964 
3965                 IkeEapPayload ikeEapPayload =
3966                         ikeMessage.getPayloadForType(
3967                                 IkePayload.PAYLOAD_TYPE_EAP, IkeEapPayload.class);
3968                 if (ikeEapPayload == null) {
3969                     return MsgValidationResult.newResultInvalidMsg(
3970                             new AuthenticationFailedException("Missing EAP payload"));
3971                 }
3972 
3973                 deferMessage(obtainMessage(CMD_EAP_START_EAP_AUTH, ikeEapPayload));
3974 
3975                 mCreateIkeLocalIkeAuthInEap.setIkeSetupData(
3976                         new IkeAuthData(
3977                                 mSetupData, mInitIdPayload, mRespIdPayload, mFirstChildReqList));
3978                 transitionTo(mCreateIkeLocalIkeAuthInEap);
3979             } else {
3980                 try {
3981                     maybeEnableMobility();
3982                 } catch (IkeException e) {
3983                     return MsgValidationResult.newResultInvalidMsg(e);
3984                 }
3985 
3986                 notifyIkeSessionSetup(ikeMessage);
3987                 performFirstChildNegotiation(
3988                         childReqList, extractChildPayloadsFromMessage(ikeMessage));
3989             }
3990 
3991             return MsgValidationResult.newResultOk();
3992         }
3993 
3994         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException)3995         protected void handleResponseGenericProcessError(
3996                 IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
3997             if (!mUseEap) {
3998                 // Notify the remote because they may have set up the IKE SA.
3999                 sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
4000             }
4001             handleIkeFatalError(ikeException);
4002         }
4003 
buildIkeAuthReq()4004         private IkeMessage buildIkeAuthReq()
4005                 throws SpiUnavailableException, ResourceUnavailableException {
4006             List<IkePayload> payloadList = new LinkedList<>();
4007 
4008             // Build Identification payloads
4009             mInitIdPayload =
4010                     new IkeIdPayload(
4011                             true /*isInitiator*/, mIkeSessionParams.getLocalIdentification());
4012             IkeIdPayload respIdPayload =
4013                     new IkeIdPayload(
4014                             false /*isInitiator*/, mIkeSessionParams.getRemoteIdentification());
4015             payloadList.add(mInitIdPayload);
4016             payloadList.add(respIdPayload);
4017 
4018             if (mIkeSessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH)) {
4019                 payloadList.add(new IkeNotifyPayload(NOTIFY_TYPE_EAP_ONLY_AUTHENTICATION));
4020             }
4021 
4022             // Include NOTIFY_TYPE_MOBIKE_SUPPORTED only if IKE_OPTION_MOBIKE is set.
4023             if (mIkeSessionParams.hasIkeOption(IKE_OPTION_MOBIKE)) {
4024                 payloadList.add(new IkeNotifyPayload(NOTIFY_TYPE_MOBIKE_SUPPORTED));
4025             }
4026 
4027             if (mIkeSessionParams.hasIkeOption(IKE_OPTION_INITIAL_CONTACT)) {
4028                 payloadList.add(new IkeNotifyPayload(NOTIFY_TYPE_INITIAL_CONTACT));
4029             }
4030 
4031             // Build Authentication payload
4032             IkeAuthConfig authConfig = mIkeSessionParams.getLocalAuthConfig();
4033             switch (authConfig.mAuthMethod) {
4034                 case IkeSessionParams.IKE_AUTH_METHOD_PSK:
4035                     IkeAuthPskPayload pskPayload =
4036                             new IkeAuthPskPayload(
4037                                     ((IkeAuthPskConfig) authConfig).mPsk,
4038                                     mSetupData.ikeInitRequestBytes,
4039                                     mCurrentIkeSaRecord.nonceResponder,
4040                                     mInitIdPayload.getEncodedPayloadBody(),
4041                                     mIkePrf,
4042                                     mCurrentIkeSaRecord.getSkPi());
4043                     payloadList.add(pskPayload);
4044                     break;
4045                 case IkeSessionParams.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE:
4046                     IkeAuthDigitalSignLocalConfig localAuthConfig =
4047                             (IkeAuthDigitalSignLocalConfig) mIkeSessionParams.getLocalAuthConfig();
4048 
4049                     // Add certificates to list
4050                     payloadList.add(
4051                             new IkeCertX509CertPayload(localAuthConfig.getClientEndCertificate()));
4052                     for (X509Certificate intermediateCert : localAuthConfig.mIntermediateCerts) {
4053                         payloadList.add(new IkeCertX509CertPayload(intermediateCert));
4054                     }
4055 
4056                     IkeAuthDigitalSignPayload digitalSignaturePayload =
4057                             new IkeAuthDigitalSignPayload(
4058                                     mSetupData.peerSignatureHashAlgorithms,
4059                                     localAuthConfig.mPrivateKey,
4060                                     mSetupData.ikeInitRequestBytes,
4061                                     mCurrentIkeSaRecord.nonceResponder,
4062                                     mInitIdPayload.getEncodedPayloadBody(),
4063                                     mIkePrf,
4064                                     mCurrentIkeSaRecord.getSkPi());
4065                     payloadList.add(digitalSignaturePayload);
4066 
4067                     break;
4068                 case IkeSessionParams.IKE_AUTH_METHOD_EAP:
4069                     // Do not include AUTH payload when using EAP.
4070                     break;
4071                 default:
4072                     cleanUpAndQuit(
4073                             new IllegalArgumentException(
4074                                     "Unrecognized authentication method: "
4075                                             + authConfig.mAuthMethod));
4076             }
4077 
4078             payloadList.addAll(
4079                     CreateChildSaHelper.getInitChildCreateReqPayloads(
4080                             mIkeContext.getRandomnessFactory(),
4081                             mIpSecSpiGenerator,
4082                             mIkeConnectionCtrl.getLocalAddress(),
4083                             mSetupData.firstChildSessionParams,
4084                             true /*isFirstChildSa*/));
4085 
4086             final List<ConfigAttribute> configAttributes = new ArrayList<>();
4087             configAttributes.addAll(
4088                     Arrays.asList(
4089                             CreateChildSaHelper.getConfigAttributes(
4090                                     mSetupData.firstChildSessionParams)));
4091             configAttributes.addAll(
4092                     Arrays.asList(mIkeSessionParams.getConfigurationAttributesInternal()));
4093             // Always request app version
4094             configAttributes.add(new IkeConfigPayload.ConfigAttributeAppVersion());
4095             payloadList.add(new IkeConfigPayload(false /*isReply*/, configAttributes));
4096 
4097             // Add 3GPP-specific payloads for this exchange subtype
4098             payloadList.addAll(
4099                     mIke3gppExtensionExchange.getRequestPayloads(IKE_EXCHANGE_SUBTYPE_IKE_AUTH));
4100 
4101             return buildIkeAuthReqMessage(payloadList);
4102         }
4103 
validateIkeAuthResp(IkeMessage authResp)4104         private MsgValidationResult validateIkeAuthResp(IkeMessage authResp) {
4105             // Validate IKE Authentication
4106             IkeAuthPayload authPayload = null;
4107             List<IkeCertPayload> certPayloads = new LinkedList<>();
4108 
4109             // Process 3GPP-specific payloads before verifying IKE_AUTH to ensure that the
4110             // caller is informed of them.
4111             List<IkePayload> ike3gppPayloads = null;
4112             try {
4113                 ike3gppPayloads =
4114                         handle3gppRespAndExtractNonError3gppPayloads(
4115                                 IKE_EXCHANGE_SUBTYPE_IKE_AUTH, authResp.ikePayloadList);
4116             } catch (InvalidSyntaxException e) {
4117                 return MsgValidationResult.newResultInvalidMsg(e);
4118             }
4119 
4120             List<IkePayload> payloadsWithout3gpp = new ArrayList<>(authResp.ikePayloadList);
4121             payloadsWithout3gpp.removeAll(ike3gppPayloads);
4122 
4123             for (IkePayload payload : payloadsWithout3gpp) {
4124                 switch (payload.payloadType) {
4125                     case IkePayload.PAYLOAD_TYPE_ID_RESPONDER:
4126                         mRespIdPayload = (IkeIdPayload) payload;
4127                         if (!mIkeSessionParams.hasIkeOption(
4128                                         IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
4129                                 && !mIkeSessionParams
4130                                         .getRemoteIdentification()
4131                                         .equals(mRespIdPayload.ikeId)) {
4132                             return MsgValidationResult.newResultInvalidMsg(
4133                                     new AuthenticationFailedException(
4134                                             "Unrecognized Responder Identification."));
4135                         }
4136                         break;
4137                     case IkePayload.PAYLOAD_TYPE_AUTH:
4138                         authPayload = (IkeAuthPayload) payload;
4139                         break;
4140                     case IkePayload.PAYLOAD_TYPE_CERT:
4141                         certPayloads.add((IkeCertPayload) payload);
4142                         break;
4143                     case IkePayload.PAYLOAD_TYPE_NOTIFY:
4144                         MsgValidationResult result =
4145                                 handleNotifyInLastAuthResp(
4146                                         (IkeNotifyPayload) payload,
4147                                         authResp.getPayloadForType(
4148                                                 PAYLOAD_TYPE_AUTH, IkeAuthPayload.class));
4149                         if (result.getResult() != MsgValidationResult.RESULT_OK) {
4150                             return result;
4151                         }
4152                         break;
4153                     case PAYLOAD_TYPE_SA: // Will be handled separately; fall through
4154                     case PAYLOAD_TYPE_CP: // Will be handled separately; fall through
4155                     case PAYLOAD_TYPE_TS_INITIATOR: // Will be handled separately; fall through
4156                     case PAYLOAD_TYPE_TS_RESPONDER: // Will be handled separately; fall through
4157                     case PAYLOAD_TYPE_EAP: // Will be handled separately
4158                         break;
4159                     default:
4160                         logw(
4161                                 "Received unexpected payload in IKE AUTH response. Payload"
4162                                         + " type: "
4163                                         + payload.payloadType);
4164                 }
4165             }
4166 
4167             // Verify existence of payloads
4168             if (authPayload == null && mIkeSessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH)) {
4169                 // If EAP-only option is selected, the responder will not send auth payload if it
4170                 // accepts EAP-only authentication. Currently only EAP-only safe methods are
4171                 // proposed to the responder if IKE_OPTION_EAP_ONLY_AUTH option is set. So there is
4172                 // no need to check if the responder selected an EAP-only safe method
4173                 return MsgValidationResult.newResultOk();
4174             }
4175 
4176             try {
4177                 // Authenticate the remote peer.
4178                 if (authPayload != null && mRespIdPayload != null) {
4179                     authenticate(authPayload, mRespIdPayload, certPayloads);
4180                     return MsgValidationResult.newResultOk();
4181                 }
4182             } catch (AuthenticationFailedException e) {
4183                 return MsgValidationResult.newResultInvalidMsg(e);
4184             }
4185 
4186             return MsgValidationResult.newResultInvalidMsg(
4187                     new AuthenticationFailedException("ID-Responder or Auth payload is missing."));
4188         }
4189 
authenticate( IkeAuthPayload authPayload, IkeIdPayload respIdPayload, List<IkeCertPayload> certPayloads)4190         private void authenticate(
4191                 IkeAuthPayload authPayload,
4192                 IkeIdPayload respIdPayload,
4193                 List<IkeCertPayload> certPayloads)
4194                 throws AuthenticationFailedException {
4195             switch (mIkeSessionParams.getRemoteAuthConfig().mAuthMethod) {
4196                 case IkeSessionParams.IKE_AUTH_METHOD_PSK:
4197                     authenticatePsk(
4198                             ((IkeAuthPskConfig) mIkeSessionParams.getRemoteAuthConfig()).mPsk,
4199                             authPayload,
4200                             respIdPayload);
4201                     break;
4202                 case IkeSessionParams.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE:
4203                     authenticateDigitalSignature(
4204                             certPayloads,
4205                             ((IkeAuthDigitalSignRemoteConfig)
4206                                             mIkeSessionParams.getRemoteAuthConfig())
4207                                     .mTrustAnchor,
4208                             authPayload,
4209                             respIdPayload);
4210                     break;
4211                 default:
4212                     cleanUpAndQuit(
4213                             new IllegalArgumentException(
4214                                     "Unrecognized auth method: " + authPayload.authMethod));
4215             }
4216         }
4217 
authenticateDigitalSignature( List<IkeCertPayload> certPayloads, TrustAnchor trustAnchor, IkeAuthPayload authPayload, IkeIdPayload respIdPayload)4218         private void authenticateDigitalSignature(
4219                 List<IkeCertPayload> certPayloads,
4220                 TrustAnchor trustAnchor,
4221                 IkeAuthPayload authPayload,
4222                 IkeIdPayload respIdPayload)
4223                 throws AuthenticationFailedException {
4224             if (authPayload.authMethod != IkeAuthPayload.AUTH_METHOD_RSA_DIGITAL_SIGN
4225                     && authPayload.authMethod != IkeAuthPayload.AUTH_METHOD_GENERIC_DIGITAL_SIGN) {
4226                 throw new AuthenticationFailedException(
4227                         "Expected the remote/server to use digital-signature-based authentication"
4228                                 + " but they used: "
4229                                 + authPayload.authMethod);
4230             }
4231 
4232             X509Certificate endCert = null;
4233             List<X509Certificate> certList = new LinkedList<>();
4234 
4235             // TODO: b/122676944 Extract CRL from IkeCrlPayload when we support IkeCrlPayload
4236             for (IkeCertPayload certPayload : certPayloads) {
4237                 X509Certificate cert = ((IkeCertX509CertPayload) certPayload).certificate;
4238 
4239                 // The first certificate MUST be the end entity certificate.
4240                 if (endCert == null) endCert = cert;
4241                 certList.add(cert);
4242             }
4243 
4244             if (endCert == null) {
4245                 throw new AuthenticationFailedException(
4246                         "The remote/server failed to provide a end certificate");
4247             }
4248 
4249             respIdPayload.validateEndCertIdOrThrow(endCert);
4250 
4251             Set<TrustAnchor> trustAnchorSet =
4252                     trustAnchor == null ? null : Collections.singleton(trustAnchor);
4253 
4254             IkeCertPayload.validateCertificates(
4255                     endCert, certList, null /*crlList*/, trustAnchorSet);
4256 
4257             IkeAuthDigitalSignPayload signPayload = (IkeAuthDigitalSignPayload) authPayload;
4258             signPayload.verifyInboundSignature(
4259                     endCert,
4260                     mSetupData.ikeInitResponseBytes,
4261                     mCurrentIkeSaRecord.nonceInitiator,
4262                     respIdPayload.getEncodedPayloadBody(),
4263                     mIkePrf,
4264                     mCurrentIkeSaRecord.getSkPr());
4265         }
4266 
4267         @Override
exitState()4268         public void exitState() {
4269             if (mIsClosing && mFirstChildReqList != null) {
4270                 CreateChildSaHelper.releaseSpiResources(mFirstChildReqList);
4271             }
4272             super.exitState();
4273         }
4274     }
4275 
4276     /**
4277      * CreateIkeLocalIkeAuthInEap represents the state when the IKE library authenticates the client
4278      * with an EAP session.
4279      */
4280     class CreateIkeLocalIkeAuthInEap extends CreateIkeLocalIkeAuthBase<IkeAuthData> {
4281         private EapAuthenticator mEapAuthenticator;
4282 
4283         @Override
enterState()4284         public void enterState() {
4285             IkeSessionParams.IkeAuthEapConfig ikeAuthEapConfig =
4286                     (IkeSessionParams.IkeAuthEapConfig) mIkeSessionParams.getLocalAuthConfig();
4287 
4288             // TODO(b/148689509): Pass in deterministic random when test mode is enabled
4289             mEapAuthenticator =
4290                     mDeps.newEapAuthenticator(
4291                             mIkeContext, new IkeEapCallback(), ikeAuthEapConfig.mEapConfig);
4292         }
4293 
4294         @Override
processStateMessage(Message msg)4295         public boolean processStateMessage(Message msg) {
4296             switch (msg.what) {
4297                 case CMD_EAP_START_EAP_AUTH:
4298                     IkeEapPayload ikeEapPayload = (IkeEapPayload) msg.obj;
4299                     mEapAuthenticator.processEapMessage(ikeEapPayload.eapMessage);
4300 
4301                     return HANDLED;
4302                 case CMD_EAP_OUTBOUND_MSG_READY:
4303                     IkeEapOutboundMsgWrapper msgWrapper = (IkeEapOutboundMsgWrapper) msg.obj;
4304                     IkeEapPayload eapPayload = new IkeEapPayload(msgWrapper.getEapMsg());
4305 
4306                     List<IkePayload> payloadList = new LinkedList<>();
4307                     payloadList.add(eapPayload);
4308 
4309                     // Add 3GPP-specific payloads for this exchange subtype
4310                     payloadList.addAll(
4311                             mIke3gppExtensionExchange.getRequestPayloadsInEap(
4312                                     msgWrapper.isServerAuthenticated()));
4313 
4314                     // Setup new retransmitter with EAP response
4315                     mRetransmitter =
4316                             new EncryptedRetransmitter(buildIkeAuthReqMessage(payloadList));
4317 
4318                     return HANDLED;
4319                 case CMD_EAP_ERRORED:
4320                     handleIkeFatalError(new AuthenticationFailedException((Throwable) msg.obj));
4321                     return HANDLED;
4322                 case CMD_EAP_FAILED:
4323                     AuthenticationFailedException exception =
4324                             new AuthenticationFailedException("EAP Authentication Failed");
4325 
4326                     handleIkeFatalError(exception);
4327                     return HANDLED;
4328                 case CMD_EAP_FINISH_EAP_AUTH:
4329                     deferMessage(msg);
4330                     mCreateIkeLocalIkeAuthPostEap.setIkeSetupData(mSetupData);
4331                     transitionTo(mCreateIkeLocalIkeAuthPostEap);
4332 
4333                     return HANDLED;
4334                 case CMD_SET_NETWORK:
4335                     // Shouldn't be receiving this command before MOBIKE is active - determined with
4336                     // last IKE_AUTH response
4337                     logWtf("Received SET_NETWORK cmd in " + getCurrentStateName());
4338                     return NOT_HANDLED;
4339                 default:
4340                     return super.processStateMessage(msg);
4341             }
4342         }
4343 
4344         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)4345         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
4346             try {
4347                 mRetransmitter.stopRetransmitting();
4348 
4349                 int exchangeType = ikeMessage.ikeHeader.exchangeType;
4350                 if (exchangeType != IkeHeader.EXCHANGE_TYPE_IKE_AUTH) {
4351                     throw new InvalidSyntaxException(
4352                             "Expected EXCHANGE_TYPE_IKE_AUTH but received: " + exchangeType);
4353                 }
4354 
4355                 // Process 3GPP-specific payloads before verifying IKE_AUTH to ensure that the
4356                 // caller is informed of them.
4357                 List<IkePayload> ike3gppPayloads =
4358                         handle3gppRespAndExtractNonError3gppPayloads(
4359                                 IKE_EXCHANGE_SUBTYPE_IKE_AUTH, ikeMessage.ikePayloadList);
4360 
4361                 List<IkePayload> payloadsWithout3gpp = new ArrayList<>(ikeMessage.ikePayloadList);
4362                 payloadsWithout3gpp.removeAll(ike3gppPayloads);
4363 
4364                 IkeEapPayload eapPayload = null;
4365                 for (IkePayload payload : payloadsWithout3gpp) {
4366                     switch (payload.payloadType) {
4367                         case IkePayload.PAYLOAD_TYPE_EAP:
4368                             eapPayload = (IkeEapPayload) payload;
4369                             break;
4370                         case IkePayload.PAYLOAD_TYPE_NOTIFY:
4371                             IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
4372                             if (notifyPayload.isErrorNotify()) {
4373                                 throw notifyPayload.validateAndBuildIkeException();
4374                             } else {
4375                                 // Unknown and unexpected status notifications are ignored as per
4376                                 // RFC7296.
4377                                 logw(
4378                                         "Received unknown or unexpected status notifications with"
4379                                                 + " notify type: "
4380                                                 + notifyPayload.notifyType);
4381                             }
4382                             break;
4383                         default:
4384                             logw(
4385                                     "Received unexpected payload in IKE AUTH response. Payload"
4386                                             + " type: "
4387                                             + payload.payloadType);
4388                     }
4389                 }
4390 
4391                 if (eapPayload == null) {
4392                     throw new AuthenticationFailedException("EAP Payload is missing.");
4393                 }
4394 
4395                 mEapAuthenticator.processEapMessage(eapPayload.eapMessage);
4396             } catch (IkeProtocolException exception) {
4397                 handleIkeFatalError(exception);
4398             }
4399         }
4400 
4401         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException)4402         protected void handleResponseGenericProcessError(
4403                 IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
4404             mRetransmitter.stopRetransmitting();
4405             handleIkeFatalError(ikeException);
4406         }
4407 
4408         private class IkeEapCallback implements IEapCallback {
4409             @Override
onSuccess(byte[] msk, byte[] emsk, @Nullable EapInfo eapInfo)4410             public void onSuccess(byte[] msk, byte[] emsk, @Nullable EapInfo eapInfo) {
4411                 // Extended MSK not used in IKEv2, drop.
4412                 mCreateIkeLocalIkeAuthPostEap.setEapInfo(eapInfo);
4413                 sendMessage(CMD_EAP_FINISH_EAP_AUTH, msk);
4414             }
4415 
4416             @Override
onFail()4417             public void onFail() {
4418                 sendMessage(CMD_EAP_FAILED);
4419             }
4420 
4421             @Override
onResponse(byte[] eapMsg, int flagMask)4422             public void onResponse(byte[] eapMsg, int flagMask) {
4423 
4424                 // for now we only check if server is authenticated for EAP-AKA
4425                 boolean serverAuthenticated =
4426                         EapResult.EapResponse.hasFlag(
4427                                 flagMask,
4428                                 EapResult.EapResponse.RESPONSE_FLAG_EAP_AKA_SERVER_AUTHENTICATED);
4429                 IkeEapOutboundMsgWrapper msg =
4430                         new IkeEapOutboundMsgWrapper(serverAuthenticated, eapMsg);
4431                 sendMessage(CMD_EAP_OUTBOUND_MSG_READY, msg);
4432             }
4433 
4434             @Override
onError(Throwable cause)4435             public void onError(Throwable cause) {
4436                 sendMessage(CMD_EAP_ERRORED, cause);
4437             }
4438         }
4439 
4440         @Override
exitState()4441         public void exitState() {
4442             if (mIsClosing) {
4443                 CreateChildSaHelper.releaseSpiResources(mSetupData.firstChildReqList);
4444             }
4445             super.exitState();
4446         }
4447     }
4448 
4449     /**
4450      * CreateIkeLocalIkeAuthPostEap represents the state when the IKE library is performing the
4451      * post-EAP PSK-base authentication run.
4452      */
4453     class CreateIkeLocalIkeAuthPostEap
4454             extends CreateIkeLocalIkeAuthFirstAndLastExchangeBase<IkeAuthData> {
4455         private byte[] mEapMsk = new byte[0];
4456 
4457         @Override
processStateMessage(Message msg)4458         public boolean processStateMessage(Message msg) {
4459             switch (msg.what) {
4460                 case CMD_EAP_FINISH_EAP_AUTH:
4461                     mEapMsk = (byte[]) msg.obj;
4462 
4463                     IkeAuthPskPayload pskPayload =
4464                             new IkeAuthPskPayload(
4465                                     mEapMsk,
4466                                     mSetupData.ikeInitRequestBytes,
4467                                     mCurrentIkeSaRecord.nonceResponder,
4468                                     mSetupData.initIdPayload.getEncodedPayloadBody(),
4469                                     mIkePrf,
4470                                     mCurrentIkeSaRecord.getSkPi());
4471                     IkeMessage postEapAuthMsg = buildIkeAuthReqMessage(Arrays.asList(pskPayload));
4472                     mRetransmitter = new EncryptedRetransmitter(postEapAuthMsg);
4473 
4474                     return HANDLED;
4475                 case CMD_SET_NETWORK:
4476                     // Shouldn't be receiving this command before MOBIKE is active - determined with
4477                     // last IKE_AUTH response
4478                     logWtf("Received SET_NETWORK cmd in " + getCurrentStateName());
4479                     return NOT_HANDLED;
4480                 default:
4481                     return super.processStateMessage(msg);
4482             }
4483         }
4484 
4485         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)4486         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
4487             handleIkeAuthResponse(ikeMessage, true /* isServerExpectingMoreEap */);
4488         }
4489 
4490         @Override
validateAuthRespAndTakeNextStep(IkeMessage ikeMessage)4491         public MsgValidationResult validateAuthRespAndTakeNextStep(IkeMessage ikeMessage) {
4492             MsgValidationResult validateResult = validateIkeAuthResp(ikeMessage);
4493             if (validateResult.getResult() != MsgValidationResult.RESULT_OK) {
4494                 return validateResult;
4495             }
4496 
4497             try {
4498                 maybeEnableMobility();
4499             } catch (IkeException e) {
4500                 MsgValidationResult.newResultInvalidMsg(e);
4501             }
4502 
4503             notifyIkeSessionSetup(ikeMessage);
4504             performFirstChildNegotiation(
4505                     mSetupData.firstChildReqList, extractChildPayloadsFromMessage(ikeMessage));
4506             return MsgValidationResult.newResultOk();
4507         }
4508 
4509         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException)4510         protected void handleResponseGenericProcessError(
4511                 IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
4512             mRetransmitter.stopRetransmitting();
4513             // Notify the remote because they may have set up the IKE SA.
4514             sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
4515             handleIkeFatalError(ikeException);
4516         }
4517 
validateIkeAuthResp(IkeMessage authResp)4518         private MsgValidationResult validateIkeAuthResp(IkeMessage authResp) {
4519             IkeAuthPayload authPayload = null;
4520 
4521             // Process 3GPP-specific payloads before verifying IKE_AUTH to ensure that the
4522             // caller is informed of them.
4523             List<IkePayload> ike3gppPayloads = null;
4524             try {
4525                 ike3gppPayloads =
4526                         handle3gppRespAndExtractNonError3gppPayloads(
4527                                 IKE_EXCHANGE_SUBTYPE_IKE_AUTH, authResp.ikePayloadList);
4528             } catch (InvalidSyntaxException e) {
4529                 return MsgValidationResult.newResultInvalidMsg(e);
4530             }
4531 
4532             List<IkePayload> payloadsWithout3gpp = new ArrayList<>(authResp.ikePayloadList);
4533             payloadsWithout3gpp.removeAll(ike3gppPayloads);
4534 
4535             for (IkePayload payload : payloadsWithout3gpp) {
4536                 switch (payload.payloadType) {
4537                     case IkePayload.PAYLOAD_TYPE_AUTH:
4538                         authPayload = (IkeAuthPayload) payload;
4539                         break;
4540                     case IkePayload.PAYLOAD_TYPE_NOTIFY:
4541                         MsgValidationResult result =
4542                                 handleNotifyInLastAuthResp(
4543                                         (IkeNotifyPayload) payload,
4544                                         authResp.getPayloadForType(
4545                                                 PAYLOAD_TYPE_AUTH, IkeAuthPayload.class));
4546                         if (result.getResult() != MsgValidationResult.RESULT_OK) {
4547                             return result;
4548                         }
4549                         break;
4550                     case PAYLOAD_TYPE_SA: // Will be handled separately; fall through
4551                     case PAYLOAD_TYPE_CP: // Will be handled separately; fall through
4552                     case PAYLOAD_TYPE_TS_INITIATOR: // Will be handled separately; fall through
4553                     case PAYLOAD_TYPE_TS_RESPONDER: // Will be handled separately; fall through
4554                         break;
4555                     default:
4556                         logw(
4557                                 "Received unexpected payload in IKE AUTH response. Payload"
4558                                         + " type: "
4559                                         + payload.payloadType);
4560                 }
4561             }
4562 
4563             // Verify existence of payloads
4564             if (authPayload == null) {
4565                 return MsgValidationResult.newResultInvalidMsg(
4566                         new AuthenticationFailedException("Post-EAP Auth payload missing."));
4567             }
4568 
4569             try {
4570                 authenticatePsk(mEapMsk, authPayload, mSetupData.respIdPayload);
4571                 return MsgValidationResult.newResultOk();
4572             } catch (AuthenticationFailedException e) {
4573                 return MsgValidationResult.newResultInvalidMsg(e);
4574             }
4575         }
4576 
4577         @Override
exitState()4578         public void exitState() {
4579             if (mIsClosing) {
4580                 CreateChildSaHelper.releaseSpiResources(mSetupData.firstChildReqList);
4581             }
4582             super.exitState();
4583         }
4584     }
4585 
4586     private abstract class RekeyIkeHandlerBase extends DeleteBase {
validateIkeRekeyCommon(IkeMessage ikeMessage)4587         private void validateIkeRekeyCommon(IkeMessage ikeMessage) throws InvalidSyntaxException {
4588             boolean hasSaPayload = false;
4589             boolean hasKePayload = false;
4590             boolean hasNoncePayload = false;
4591             for (IkePayload payload : ikeMessage.ikePayloadList) {
4592                 switch (payload.payloadType) {
4593                     case IkePayload.PAYLOAD_TYPE_SA:
4594                         hasSaPayload = true;
4595                         break;
4596                     case IkePayload.PAYLOAD_TYPE_KE:
4597                         hasKePayload = true;
4598                         break;
4599                     case IkePayload.PAYLOAD_TYPE_NONCE:
4600                         hasNoncePayload = true;
4601                         break;
4602                     case IkePayload.PAYLOAD_TYPE_VENDOR:
4603                         // Vendor payloads allowed, but not verified
4604                         break;
4605                     case IkePayload.PAYLOAD_TYPE_NOTIFY:
4606                         // Notification payloads allowed, but left to handler methods to process.
4607                         break;
4608                     default:
4609                         logw(
4610                                 "Received unexpected payload in IKE REKEY request. Payload type: "
4611                                         + payload.payloadType);
4612                 }
4613             }
4614 
4615             if (!hasSaPayload || !hasKePayload || !hasNoncePayload) {
4616                 throw new InvalidSyntaxException("SA, KE or Nonce payload missing.");
4617             }
4618         }
4619 
4620         @VisibleForTesting
validateIkeRekeyReq(IkeMessage ikeMessage)4621         void validateIkeRekeyReq(IkeMessage ikeMessage) throws InvalidSyntaxException {
4622             // Skip validation of exchange type since it has been done during decoding request.
4623 
4624             List<IkeNotifyPayload> notificationPayloads =
4625                     ikeMessage.getPayloadListForType(
4626                             IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
4627             for (IkeNotifyPayload notifyPayload : notificationPayloads) {
4628                 if (notifyPayload.isErrorNotify()) {
4629                     logw("Error notifications invalid in request: " + notifyPayload.notifyType);
4630                 }
4631             }
4632 
4633             validateIkeRekeyCommon(ikeMessage);
4634         }
4635 
4636         @VisibleForTesting
validateIkeRekeyResp(IkeMessage reqMsg, IkeMessage respMsg)4637         void validateIkeRekeyResp(IkeMessage reqMsg, IkeMessage respMsg)
4638                 throws InvalidSyntaxException {
4639             int exchangeType = respMsg.ikeHeader.exchangeType;
4640             if (exchangeType != IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA
4641                     && exchangeType != IkeHeader.EXCHANGE_TYPE_INFORMATIONAL) {
4642                 throw new InvalidSyntaxException(
4643                         "Expected Rekey response (CREATE_CHILD_SA or INFORMATIONAL) but received: "
4644                                 + exchangeType);
4645             }
4646 
4647             List<IkeNotifyPayload> notificationPayloads =
4648                     respMsg.getPayloadListForType(
4649                             IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
4650             for (IkeNotifyPayload notifyPayload : notificationPayloads) {
4651                 if (notifyPayload.isErrorNotify()) {
4652                     // Error notifications found. Stop validation for SA negotiation.
4653                     return;
4654                 }
4655             }
4656 
4657             validateIkeRekeyCommon(respMsg);
4658 
4659             // Verify DH groups matching
4660             IkeKePayload reqKePayload =
4661                     reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
4662             IkeKePayload respKePayload =
4663                     respMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
4664             if (reqKePayload.dhGroup != respKePayload.dhGroup) {
4665                 throw new InvalidSyntaxException("Received KE payload with mismatched DH group.");
4666             }
4667         }
4668 
4669         // It doesn't make sense to include multiple error notify payloads in one response. If it
4670         // happens, IKE Session will only handle the most severe one.
handleErrorNotifyIfExists(IkeMessage respMsg, boolean isSimulRekey)4671         protected boolean handleErrorNotifyIfExists(IkeMessage respMsg, boolean isSimulRekey) {
4672             IkeNotifyPayload invalidSyntaxNotifyPayload = null;
4673             IkeNotifyPayload tempFailureNotifyPayload = null;
4674             IkeNotifyPayload firstErrorNotifyPayload = null;
4675 
4676             List<IkeNotifyPayload> notificationPayloads =
4677                     respMsg.getPayloadListForType(
4678                             IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
4679             for (IkeNotifyPayload notifyPayload : notificationPayloads) {
4680                 if (!notifyPayload.isErrorNotify()) continue;
4681 
4682                 if (firstErrorNotifyPayload == null) firstErrorNotifyPayload = notifyPayload;
4683 
4684                 if (ERROR_TYPE_INVALID_SYNTAX == notifyPayload.notifyType) {
4685                     invalidSyntaxNotifyPayload = notifyPayload;
4686                 } else if (ERROR_TYPE_TEMPORARY_FAILURE == notifyPayload.notifyType) {
4687                     tempFailureNotifyPayload = notifyPayload;
4688                 }
4689             }
4690 
4691             // No error Notify Payload included in this response.
4692             if (firstErrorNotifyPayload == null) return NOT_HANDLED;
4693 
4694             // Handle Invalid Syntax if it exists
4695             if (invalidSyntaxNotifyPayload != null) {
4696                 try {
4697                     IkeProtocolException exception =
4698                             invalidSyntaxNotifyPayload.validateAndBuildIkeException();
4699                     handleIkeFatalError(exception);
4700                 } catch (InvalidSyntaxException e) {
4701                     // Error notify payload has invalid syntax
4702                     handleIkeFatalError(e);
4703                 }
4704                 return HANDLED;
4705             }
4706 
4707             if (tempFailureNotifyPayload != null) {
4708                 // Handle Temporary Failure if exists
4709                 loge("Received TEMPORARY_FAILURE for rekey IKE. Already handled during decoding.");
4710             } else {
4711                 // Handle other errors
4712                 loge(
4713                         "Received error notification: "
4714                                 + firstErrorNotifyPayload.notifyType
4715                                 + " for rekey IKE. Schedule a retry");
4716                 if (!isSimulRekey) {
4717                     mCurrentIkeSaRecord.rescheduleRekey(RETRY_INTERVAL_MS);
4718                 }
4719             }
4720 
4721             if (isSimulRekey) {
4722                 transitionTo(mRekeyIkeRemoteDelete);
4723             } else {
4724                 transitionTo(mIdle);
4725             }
4726             return HANDLED;
4727         }
4728 
validateAndBuildIkeSa( IkeMessage reqMsg, IkeMessage respMessage, boolean isLocalInit)4729         protected IkeSaRecord validateAndBuildIkeSa(
4730                 IkeMessage reqMsg, IkeMessage respMessage, boolean isLocalInit)
4731                 throws IkeProtocolException, GeneralSecurityException, IOException {
4732             InetAddress initAddr =
4733                     isLocalInit
4734                             ? mIkeConnectionCtrl.getLocalAddress()
4735                             : mIkeConnectionCtrl.getRemoteAddress();
4736             InetAddress respAddr =
4737                     isLocalInit
4738                             ? mIkeConnectionCtrl.getRemoteAddress()
4739                             : mIkeConnectionCtrl.getLocalAddress();
4740 
4741             Pair<IkeProposal, IkeProposal> negotiatedProposals = null;
4742             try {
4743                 IkeSaPayload reqSaPayload =
4744                         reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
4745                 IkeSaPayload respSaPayload =
4746                         respMessage.getPayloadForType(
4747                                 IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
4748 
4749                 // Throw exception or return valid negotiated proposal with allocated SPIs
4750                 negotiatedProposals =
4751                         IkeSaPayload.getVerifiedNegotiatedIkeProposalPair(
4752                                 reqSaPayload,
4753                                 respSaPayload,
4754                                 mIkeSpiGenerator,
4755                                 mIkeConnectionCtrl.getRemoteAddress());
4756                 IkeProposal reqProposal = negotiatedProposals.first;
4757                 IkeProposal respProposal = negotiatedProposals.second;
4758 
4759                 IkeMacPrf newPrf;
4760                 IkeCipher newCipher;
4761                 IkeMacIntegrity newIntegrity = null;
4762 
4763                 newCipher = IkeCipher.create(respProposal.saProposal.getEncryptionTransforms()[0]);
4764                 if (!newCipher.isAead()) {
4765                     newIntegrity =
4766                             IkeMacIntegrity.create(
4767                                     respProposal.saProposal.getIntegrityTransforms()[0]);
4768                 }
4769                 newPrf = IkeMacPrf.create(respProposal.saProposal.getPrfTransforms()[0]);
4770 
4771                 // Build new SaRecord
4772                 long remoteSpi =
4773                         isLocalInit
4774                                 ? respProposal.getIkeSpiResource().getSpi()
4775                                 : reqProposal.getIkeSpiResource().getSpi();
4776                 IkeSaRecord newSaRecord =
4777                         IkeSaRecord.makeRekeyedIkeSaRecord(
4778                                 mCurrentIkeSaRecord,
4779                                 mIkePrf,
4780                                 reqMsg,
4781                                 respMessage,
4782                                 reqProposal.getIkeSpiResource(),
4783                                 respProposal.getIkeSpiResource(),
4784                                 newPrf,
4785                                 newIntegrity == null ? 0 : newIntegrity.getKeyLength(),
4786                                 newCipher.getKeyLength(),
4787                                 isLocalInit,
4788                                 buildSaLifetimeAlarmScheduler(remoteSpi));
4789                 addIkeSaRecord(newSaRecord);
4790 
4791                 mIkeCipher = newCipher;
4792                 mIkePrf = newPrf;
4793                 mIkeIntegrity = newIntegrity;
4794 
4795                 return newSaRecord;
4796             } catch (IkeProtocolException | GeneralSecurityException | IOException e) {
4797                 if (negotiatedProposals != null) {
4798                     negotiatedProposals.first.getIkeSpiResource().close();
4799                     negotiatedProposals.second.getIkeSpiResource().close();
4800                 }
4801                 throw e;
4802             }
4803         }
4804     }
4805 
4806     /** RekeyIkeLocalCreate represents state when IKE library initiates Rekey IKE exchange. */
4807     class RekeyIkeLocalCreate extends RekeyIkeHandlerBase {
4808         protected Retransmitter mRetransmitter;
4809 
4810         @Override
enterState()4811         public void enterState() {
4812             try {
4813                 mRetransmitter = new EncryptedRetransmitter(buildIkeRekeyReq());
4814             } catch (IOException e) {
4815                 loge("Fail to assign IKE SPI for rekey. Schedule a retry.", e);
4816                 mCurrentIkeSaRecord.rescheduleRekey(RETRY_INTERVAL_MS);
4817                 transitionTo(mIdle);
4818             }
4819         }
4820 
4821         @Override
triggerRetransmit()4822         protected void triggerRetransmit() {
4823             mRetransmitter.retransmit();
4824         }
4825 
4826         @Override
handleTempFailure()4827         protected void handleTempFailure() {
4828             mTempFailHandler.handleTempFailure();
4829             mCurrentIkeSaRecord.rescheduleRekey(RETRY_INTERVAL_MS);
4830         }
4831 
4832         /**
4833          * Builds a IKE Rekey request, reusing the current proposal
4834          *
4835          * <p>As per RFC 7296, rekey messages are of format: { HDR { SK { SA, Ni, KEi } } }
4836          *
4837          * <p>This method currently reuses agreed upon proposal.
4838          */
buildIkeRekeyReq()4839         private IkeMessage buildIkeRekeyReq() throws IOException {
4840             // TODO: Evaluate if we need to support different proposals for rekeys
4841             IkeSaProposal[] saProposals = new IkeSaProposal[] {mSaProposal};
4842 
4843             // No need to allocate SPIs; they will be allocated as part of the
4844             // getRekeyIkeSaRequestPayloads
4845             List<IkePayload> payloadList =
4846                     CreateIkeSaHelper.getRekeyIkeSaRequestPayloads(
4847                             saProposals,
4848                             mIkeSpiGenerator,
4849                             mIkeConnectionCtrl.getLocalAddress(),
4850                             mIkeContext.getRandomnessFactory());
4851 
4852             // Build IKE header
4853             IkeHeader ikeHeader =
4854                     new IkeHeader(
4855                             mCurrentIkeSaRecord.getInitiatorSpi(),
4856                             mCurrentIkeSaRecord.getResponderSpi(),
4857                             IkePayload.PAYLOAD_TYPE_SK,
4858                             IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
4859                             false /*isResponseMsg*/,
4860                             mCurrentIkeSaRecord.isLocalInit,
4861                             mCurrentIkeSaRecord.getLocalRequestMessageId());
4862 
4863             return new IkeMessage(ikeHeader, payloadList);
4864         }
4865 
4866         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)4867         protected void handleRequestIkeMessage(
4868                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
4869             switch (ikeExchangeSubType) {
4870                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
4871                     handleDeleteSessionRequest(ikeMessage);
4872                     break;
4873                 case IKE_EXCHANGE_SUBTYPE_GENERIC_INFO:
4874                     handleGenericInfoRequest(ikeMessage);
4875                     break;
4876                 default:
4877                     // TODO: Implement simultaneous rekey
4878                     buildAndSendErrorNotificationResponse(
4879                             mCurrentIkeSaRecord,
4880                             ikeMessage.ikeHeader.messageId,
4881                             ERROR_TYPE_TEMPORARY_FAILURE);
4882             }
4883         }
4884 
4885         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)4886         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
4887             try {
4888                 // Validate syntax
4889                 validateIkeRekeyResp(mRetransmitter.getMessage(), ikeMessage);
4890 
4891                 // Handle error notifications if they exist
4892                 if (handleErrorNotifyIfExists(ikeMessage, false /*isSimulRekey*/) == NOT_HANDLED) {
4893                     // No error notifications included. Negotiate new SA
4894                     mLocalInitNewIkeSaRecord =
4895                             validateAndBuildIkeSa(
4896                                     mRetransmitter.getMessage(), ikeMessage, true /*isLocalInit*/);
4897                     transitionTo(mRekeyIkeLocalDelete);
4898                 }
4899 
4900                 // Stop retransmissions
4901                 mRetransmitter.stopRetransmitting();
4902             } catch (IkeProtocolException e) {
4903                 if (e instanceof InvalidSyntaxException) {
4904                     handleProcessRespOrSaCreationFailureAndQuit(e);
4905                 } else {
4906                     handleProcessRespOrSaCreationFailureAndQuit(
4907                             new InvalidSyntaxException(
4908                                     "Error in processing IKE Rekey-Create response", e));
4909                 }
4910 
4911             } catch (GeneralSecurityException | IOException e) {
4912                 handleProcessRespOrSaCreationFailureAndQuit(wrapAsIkeException(e));
4913             }
4914         }
4915 
4916         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException)4917         protected void handleResponseGenericProcessError(
4918                 IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
4919             handleProcessRespOrSaCreationFailureAndQuit(ikeException);
4920         }
4921 
handleProcessRespOrSaCreationFailureAndQuit(IkeException exception)4922         private void handleProcessRespOrSaCreationFailureAndQuit(IkeException exception) {
4923             // We don't retry rekey if failure was caused by invalid response or SA creation error.
4924             // Reason is there is no way to notify the remote side the old SA is still alive but the
4925             // new one has failed.
4926 
4927             mRetransmitter.stopRetransmitting();
4928 
4929             sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
4930             handleIkeFatalError(exception);
4931         }
4932     }
4933 
4934     /**
4935      * SimulRekeyIkeLocalCreate represents the state where IKE library has replied to rekey request
4936      * sent from the remote and is waiting for a rekey response for a locally initiated rekey
4937      * request.
4938      *
4939      * <p>SimulRekeyIkeLocalCreate extends RekeyIkeLocalCreate so that it can call super class to
4940      * validate incoming rekey response against locally initiated rekey request.
4941      */
4942     class SimulRekeyIkeLocalCreate extends RekeyIkeLocalCreate {
4943         @Override
enterState()4944         public void enterState() {
4945             mRetransmitter = new EncryptedRetransmitter(null);
4946             // TODO: Populate super.mRetransmitter from state initialization data
4947             // Do not send request.
4948         }
4949 
buildRequest()4950         public IkeMessage buildRequest() {
4951             throw new UnsupportedOperationException(
4952                     "Do not support sending request in " + getCurrentStateName());
4953         }
4954 
4955         @Override
exitState()4956         public void exitState() {
4957             // Do nothing.
4958         }
4959 
4960         @Override
processStateMessage(Message message)4961         public boolean processStateMessage(Message message) {
4962             switch (message.what) {
4963                 case CMD_RECEIVE_IKE_PACKET:
4964                     ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
4965                     IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
4966 
4967                     if (mRemoteInitNewIkeSaRecord == getIkeSaRecordForPacket(ikeHeader)) {
4968                         deferMessage(message);
4969                     } else {
4970                         handleReceivedIkePacket(message);
4971                     }
4972                     return HANDLED;
4973 
4974                 default:
4975                     return super.processStateMessage(message);
4976             }
4977         }
4978 
4979         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)4980         protected void handleRequestIkeMessage(
4981                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
4982             switch (ikeExchangeSubType) {
4983                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
4984                     deferMessage(message);
4985                     return;
4986                 default:
4987                     // TODO: Add more cases for other types of request.
4988             }
4989         }
4990 
4991         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)4992         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
4993             try {
4994                 validateIkeRekeyResp(mRetransmitter.getMessage(), ikeMessage);
4995 
4996                 // TODO: Check and handle error notifications before SA negotiation
4997 
4998                 mLocalInitNewIkeSaRecord =
4999                         validateAndBuildIkeSa(
5000                                 mRetransmitter.getMessage(), ikeMessage, true /*isLocalInit*/);
5001                 transitionTo(mSimulRekeyIkeLocalDeleteRemoteDelete);
5002             } catch (IkeProtocolException e) {
5003                 // TODO: Handle processing errors.
5004             } catch (GeneralSecurityException e) {
5005                 // TODO: Fatal - kill session.
5006             } catch (IOException e) {
5007                 // TODO: SPI allocation collided - delete new IKE SA, retry rekey.
5008             }
5009         }
5010     }
5011 
5012     /** RekeyIkeDeleteBase represents common behaviours of deleting stage during rekeying IKE SA. */
5013     private abstract class RekeyIkeDeleteBase extends DeleteBase {
5014         @Override
processStateMessage(Message message)5015         public boolean processStateMessage(Message message) {
5016             switch (message.what) {
5017                 case CMD_RECEIVE_IKE_PACKET:
5018                     ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
5019                     IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
5020 
5021                     // Verify that this message is correctly authenticated and encrypted:
5022                     IkeSaRecord ikeSaRecord = getIkeSaRecordForPacket(ikeHeader);
5023                     boolean isMessageOnNewSa = false;
5024                     if (ikeSaRecord != null && mIkeSaRecordSurviving == ikeSaRecord) {
5025                         DecodeResult decodeResult =
5026                                 IkeMessage.decode(
5027                                         ikeHeader.isResponseMsg
5028                                                 ? ikeSaRecord.getLocalRequestMessageId()
5029                                                 : ikeSaRecord.getRemoteRequestMessageId(),
5030                                         mIkeIntegrity,
5031                                         mIkeCipher,
5032                                         ikeSaRecord,
5033                                         ikeHeader,
5034                                         receivedIkePacket.ikePacketBytes,
5035                                         ikeSaRecord.getCollectedFragments(ikeHeader.isResponseMsg));
5036                         isMessageOnNewSa =
5037                                 (decodeResult.status == DECODE_STATUS_PROTECTED_ERROR)
5038                                         || (decodeResult.status == DECODE_STATUS_OK)
5039                                         || (decodeResult.status == DECODE_STATUS_PARTIAL);
5040                     }
5041 
5042                     // Authenticated request received on the new/surviving SA; treat it as
5043                     // an acknowledgement that the remote has successfully rekeyed.
5044                     if (isMessageOnNewSa) {
5045                         State nextState = mIdle;
5046 
5047                         // This is the first IkeMessage seen on the new SA. It cannot be a response.
5048                         // Likewise, if it a request, it must not be a retransmission. Verify msgId.
5049                         // If either condition happens, consider rekey a success, but immediately
5050                         // kill the session.
5051                         if (ikeHeader.isResponseMsg
5052                                 || ikeSaRecord.getRemoteRequestMessageId() - ikeHeader.messageId
5053                                         != 0) {
5054                             nextState = mDeleteIkeLocalDelete;
5055                         } else {
5056                             deferMessage(message);
5057                         }
5058 
5059                         // Locally close old (and losing) IKE SAs. As a result of not waiting for
5060                         // delete responses, the old SA can be left in a state where the stored ID
5061                         // is no longer correct. However, this finishRekey() call will remove that
5062                         // SA, so it doesn't matter.
5063                         finishRekey();
5064                         transitionTo(nextState);
5065                     } else {
5066                         handleReceivedIkePacket(message);
5067                     }
5068 
5069                     return HANDLED;
5070                 default:
5071                     return super.processStateMessage(message);
5072                     // TODO: Add more cases for other packet types.
5073             }
5074         }
5075 
5076         // Rekey timer for old (and losing) SAs will be cancelled as part of the closing of the SA.
finishRekey()5077         protected void finishRekey() {
5078             mCurrentIkeSaRecord = mIkeSaRecordSurviving;
5079             mLocalInitNewIkeSaRecord = null;
5080             mRemoteInitNewIkeSaRecord = null;
5081 
5082             mIkeSaRecordSurviving = null;
5083 
5084             if (mIkeSaRecordAwaitingLocalDel != null) {
5085                 removeIkeSaRecord(mIkeSaRecordAwaitingLocalDel);
5086                 mIkeSaRecordAwaitingLocalDel.close();
5087                 mIkeSaRecordAwaitingLocalDel = null;
5088             }
5089 
5090             if (mIkeSaRecordAwaitingRemoteDel != null) {
5091                 removeIkeSaRecord(mIkeSaRecordAwaitingRemoteDel);
5092                 mIkeSaRecordAwaitingRemoteDel.close();
5093                 mIkeSaRecordAwaitingRemoteDel = null;
5094             }
5095 
5096             synchronized (mChildCbToSessions) {
5097                 for (ChildSessionStateMachine child : mChildCbToSessions.values()) {
5098                     child.setSkD(mCurrentIkeSaRecord.getSkD());
5099                 }
5100             }
5101 
5102             // TODO: Update prf of all child sessions
5103         }
5104     }
5105 
5106     /**
5107      * SimulRekeyIkeLocalDeleteRemoteDelete represents the deleting stage during simultaneous
5108      * rekeying when IKE library is waiting for both a Delete request and a Delete response.
5109      */
5110     class SimulRekeyIkeLocalDeleteRemoteDelete extends RekeyIkeDeleteBase {
5111         private Retransmitter mRetransmitter;
5112 
5113         @Override
enterState()5114         public void enterState() {
5115             // Detemine surviving IKE SA. According to RFC 7296: "The new IKE SA containing the
5116             // lowest nonce SHOULD be deleted by the node that created it, and the other surviving
5117             // new IKE SA MUST inherit all the Child SAs."
5118             if (mLocalInitNewIkeSaRecord.compareTo(mRemoteInitNewIkeSaRecord) > 0) {
5119                 mIkeSaRecordSurviving = mLocalInitNewIkeSaRecord;
5120                 mIkeSaRecordAwaitingLocalDel = mCurrentIkeSaRecord;
5121                 mIkeSaRecordAwaitingRemoteDel = mRemoteInitNewIkeSaRecord;
5122             } else {
5123                 mIkeSaRecordSurviving = mRemoteInitNewIkeSaRecord;
5124                 mIkeSaRecordAwaitingLocalDel = mLocalInitNewIkeSaRecord;
5125                 mIkeSaRecordAwaitingRemoteDel = mCurrentIkeSaRecord;
5126             }
5127             mRetransmitter =
5128                     new EncryptedRetransmitter(
5129                             mIkeSaRecordAwaitingLocalDel,
5130                             buildIkeDeleteReq(mIkeSaRecordAwaitingLocalDel));
5131             // TODO: Set timer awaiting for delete request.
5132         }
5133 
5134         @Override
triggerRetransmit()5135         protected void triggerRetransmit() {
5136             mRetransmitter.retransmit();
5137         }
5138 
5139         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)5140         protected void handleRequestIkeMessage(
5141                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
5142             IkeSaRecord ikeSaRecordForPacket = getIkeSaRecordForPacket(ikeMessage.ikeHeader);
5143             switch (ikeExchangeSubType) {
5144                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
5145                     try {
5146                         validateIkeDeleteReq(ikeMessage, mIkeSaRecordAwaitingRemoteDel);
5147                         IkeMessage respMsg =
5148                                 buildIkeDeleteResp(ikeMessage, mIkeSaRecordAwaitingRemoteDel);
5149                         removeIkeSaRecord(mIkeSaRecordAwaitingRemoteDel);
5150                         // TODO: Encode and send response and close
5151                         // mIkeSaRecordAwaitingRemoteDel.
5152                         // TODO: Stop timer awating delete request.
5153                         transitionTo(mSimulRekeyIkeLocalDelete);
5154                     } catch (InvalidSyntaxException e) {
5155                         logd("Validation failed for delete request", e);
5156                         // TODO: Shutdown - fatal error
5157                     }
5158                     return;
5159                 default:
5160                     // TODO: Reply with TEMPORARY_FAILURE
5161             }
5162         }
5163 
5164         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)5165         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
5166             try {
5167                 validateIkeDeleteResp(ikeMessage, mIkeSaRecordAwaitingLocalDel);
5168                 finishDeleteIkeSaAwaitingLocalDel();
5169             } catch (InvalidSyntaxException e) {
5170                 loge("Invalid syntax on IKE Delete response. Shutting down anyways", e);
5171                 finishDeleteIkeSaAwaitingLocalDel();
5172             } catch (IllegalStateException e) {
5173                 // Response received on incorrect SA
5174                 cleanUpAndQuit(e);
5175             }
5176         }
5177 
5178         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException exception)5179         protected void handleResponseGenericProcessError(
5180                 IkeSaRecord ikeSaRecord, InvalidSyntaxException exception) {
5181             if (mIkeSaRecordAwaitingLocalDel == ikeSaRecord) {
5182                 loge("Invalid syntax on IKE Delete response. Shutting down anyways", exception);
5183                 finishDeleteIkeSaAwaitingLocalDel();
5184             } else {
5185                 cleanUpAndQuit(
5186                         new IllegalStateException("Delete response received on incorrect SA"));
5187             }
5188         }
5189 
finishDeleteIkeSaAwaitingLocalDel()5190         private void finishDeleteIkeSaAwaitingLocalDel() {
5191             mRetransmitter.stopRetransmitting();
5192 
5193             removeIkeSaRecord(mIkeSaRecordAwaitingLocalDel);
5194             mIkeSaRecordAwaitingLocalDel.close();
5195             mIkeSaRecordAwaitingLocalDel = null;
5196 
5197             transitionTo(mSimulRekeyIkeRemoteDelete);
5198         }
5199 
5200         @Override
exitState()5201         public void exitState() {
5202             finishRekey();
5203             mRetransmitter.stopRetransmitting();
5204             // TODO: Stop awaiting delete request timer.
5205         }
5206     }
5207 
5208     /**
5209      * SimulRekeyIkeLocalDelete represents the state when IKE library is waiting for a Delete
5210      * response during simultaneous rekeying.
5211      */
5212     class SimulRekeyIkeLocalDelete extends RekeyIkeDeleteBase {
5213         private Retransmitter mRetransmitter;
5214 
5215         @Override
enterState()5216         public void enterState() {
5217             mRetransmitter = new EncryptedRetransmitter(mIkeSaRecordAwaitingLocalDel, null);
5218             // TODO: Populate mRetransmitter from state initialization data.
5219         }
5220 
5221         @Override
triggerRetransmit()5222         protected void triggerRetransmit() {
5223             mRetransmitter.retransmit();
5224         }
5225 
5226         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)5227         protected void handleRequestIkeMessage(
5228                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
5229             // Always return a TEMPORARY_FAILURE. In no case should we accept a message on an SA
5230             // that is going away. All messages on the new SA is caught in RekeyIkeDeleteBase
5231             buildAndSendErrorNotificationResponse(
5232                     mIkeSaRecordAwaitingLocalDel,
5233                     ikeMessage.ikeHeader.messageId,
5234                     ERROR_TYPE_TEMPORARY_FAILURE);
5235         }
5236 
5237         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)5238         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
5239             try {
5240                 validateIkeDeleteResp(ikeMessage, mIkeSaRecordAwaitingLocalDel);
5241                 finishRekey();
5242                 transitionTo(mIdle);
5243             } catch (InvalidSyntaxException e) {
5244                 loge(
5245                         "Invalid syntax on IKE Delete response. Shutting down old IKE SA and"
5246                                 + " finishing rekey",
5247                         e);
5248                 finishRekey();
5249                 transitionTo(mIdle);
5250             } catch (IllegalStateException e) {
5251                 // Response received on incorrect SA
5252                 cleanUpAndQuit(e);
5253             }
5254         }
5255 
5256         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException exception)5257         protected void handleResponseGenericProcessError(
5258                 IkeSaRecord ikeSaRecord, InvalidSyntaxException exception) {
5259             if (mIkeSaRecordAwaitingLocalDel == ikeSaRecord) {
5260                 loge(
5261                         "Invalid syntax on IKE Delete response. Shutting down old IKE SA and"
5262                                 + " finishing rekey",
5263                         exception);
5264                 finishRekey();
5265                 transitionTo(mIdle);
5266             } else {
5267                 cleanUpAndQuit(
5268                         new IllegalStateException("Delete response received on incorrect SA"));
5269             }
5270         }
5271     }
5272 
5273     /**
5274      * SimulRekeyIkeRemoteDelete represents the state that waiting for a Delete request during
5275      * simultaneous rekeying.
5276      */
5277     class SimulRekeyIkeRemoteDelete extends RekeyIkeDeleteBase {
5278         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)5279         protected void handleRequestIkeMessage(
5280                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
5281             // At this point, the incoming request can ONLY be on mIkeSaRecordAwaitingRemoteDel - if
5282             // it was on the surviving SA, it is deferred and the rekey is finished. It is likewise
5283             // impossible to have this on the local-deleted SA, since the delete has already been
5284             // acknowledged in the SimulRekeyIkeLocalDeleteRemoteDelete state.
5285             switch (ikeExchangeSubType) {
5286                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
5287                     try {
5288                         validateIkeDeleteReq(ikeMessage, mIkeSaRecordAwaitingRemoteDel);
5289 
5290                         IkeMessage respMsg =
5291                                 buildIkeDeleteResp(ikeMessage, mIkeSaRecordAwaitingRemoteDel);
5292                         sendEncryptedIkeMessage(mIkeSaRecordAwaitingRemoteDel, respMsg);
5293 
5294                         finishRekey();
5295                         transitionTo(mIdle);
5296                     } catch (InvalidSyntaxException e) {
5297                         // Program error.
5298                         cleanUpAndQuit(new IllegalStateException(e));
5299                     }
5300                     return;
5301                 default:
5302                     buildAndSendErrorNotificationResponse(
5303                             mIkeSaRecordAwaitingRemoteDel,
5304                             ikeMessage.ikeHeader.messageId,
5305                             ERROR_TYPE_TEMPORARY_FAILURE);
5306             }
5307         }
5308     }
5309 
5310     /**
5311      * RekeyIkeLocalDelete represents the deleting stage when IKE library is initiating a Rekey
5312      * procedure.
5313      *
5314      * <p>RekeyIkeLocalDelete and SimulRekeyIkeLocalDelete have same behaviours in
5315      * processStateMessage(). While RekeyIkeLocalDelete overrides enterState() and exitState()
5316      * methods for initiating and finishing the deleting stage for IKE rekeying.
5317      */
5318     class RekeyIkeLocalDelete extends SimulRekeyIkeLocalDelete {
5319         private Retransmitter mRetransmitter;
5320 
5321         @Override
enterState()5322         public void enterState() {
5323             mIkeSaRecordSurviving = mLocalInitNewIkeSaRecord;
5324             mIkeSaRecordAwaitingLocalDel = mCurrentIkeSaRecord;
5325             mRetransmitter =
5326                     new EncryptedRetransmitter(
5327                             mIkeSaRecordAwaitingLocalDel,
5328                             buildIkeDeleteReq(mIkeSaRecordAwaitingLocalDel));
5329         }
5330 
5331         @Override
triggerRetransmit()5332         protected void triggerRetransmit() {
5333             mRetransmitter.retransmit();
5334         }
5335 
5336         @Override
exitState()5337         public void exitState() {
5338             mRetransmitter.stopRetransmitting();
5339         }
5340     }
5341 
5342     /**
5343      * RekeyIkeRemoteDelete represents the deleting stage when responding to a Rekey procedure.
5344      *
5345      * <p>RekeyIkeRemoteDelete and SimulRekeyIkeRemoteDelete have same behaviours in
5346      * processStateMessage(). While RekeyIkeLocalDelete overrides enterState() and exitState()
5347      * methods for waiting incoming delete request and for finishing the deleting stage for IKE
5348      * rekeying.
5349      */
5350     class RekeyIkeRemoteDelete extends SimulRekeyIkeRemoteDelete {
5351         @Override
enterState()5352         public void enterState() {
5353             mIkeSaRecordSurviving = mRemoteInitNewIkeSaRecord;
5354             mIkeSaRecordAwaitingRemoteDel = mCurrentIkeSaRecord;
5355 
5356             sendMessageDelayed(TIMEOUT_REKEY_REMOTE_DELETE, REKEY_DELETE_TIMEOUT_MS);
5357         }
5358 
5359         @Override
processStateMessage(Message message)5360         public boolean processStateMessage(Message message) {
5361             // Intercept rekey delete timeout. Assume rekey succeeded since no retransmissions
5362             // were received.
5363             if (message.what == TIMEOUT_REKEY_REMOTE_DELETE) {
5364                 finishRekey();
5365                 transitionTo(mIdle);
5366 
5367                 return HANDLED;
5368             } else {
5369                 return super.processStateMessage(message);
5370             }
5371         }
5372 
5373         @Override
exitState()5374         public void exitState() {
5375             removeMessages(TIMEOUT_REKEY_REMOTE_DELETE);
5376         }
5377     }
5378 
5379     /** DeleteIkeLocalDelete initiates a deletion request of the current IKE Session. */
5380     class DeleteIkeLocalDelete extends DeleteBase {
5381         private Retransmitter mRetransmitter;
5382 
5383         @Override
enterState()5384         public void enterState() {
5385             mRetransmitter = new EncryptedRetransmitter(buildIkeDeleteReq(mCurrentIkeSaRecord));
5386         }
5387 
5388         @Override
triggerRetransmit()5389         protected void triggerRetransmit() {
5390             mRetransmitter.retransmit();
5391         }
5392 
5393         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)5394         protected void handleRequestIkeMessage(
5395                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
5396             switch (ikeExchangeSubType) {
5397                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
5398                     handleDeleteSessionRequest(ikeMessage);
5399                     return;
5400                 default:
5401                     buildAndSendErrorNotificationResponse(
5402                             mCurrentIkeSaRecord,
5403                             ikeMessage.ikeHeader.messageId,
5404                             ERROR_TYPE_TEMPORARY_FAILURE);
5405             }
5406         }
5407 
5408         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)5409         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
5410             try {
5411                 validateIkeDeleteResp(ikeMessage, mCurrentIkeSaRecord);
5412                 executeUserCallback(
5413                         () -> {
5414                             mIkeSessionCallback.onClosed();
5415                         });
5416 
5417                 removeIkeSaRecord(mCurrentIkeSaRecord);
5418                 mCurrentIkeSaRecord.close();
5419                 mCurrentIkeSaRecord = null;
5420                 quitSessionNow();
5421             } catch (InvalidSyntaxException e) {
5422                 handleResponseGenericProcessError(mCurrentIkeSaRecord, e);
5423             }
5424         }
5425 
5426         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException exception)5427         protected void handleResponseGenericProcessError(
5428                 IkeSaRecord ikeSaRecord, InvalidSyntaxException exception) {
5429             loge("Invalid syntax on IKE Delete response. Shutting down anyways", exception);
5430             handleIkeFatalError(exception);
5431             quitSessionNow();
5432         }
5433 
5434         @Override
exitState()5435         public void exitState() {
5436             mRetransmitter.stopRetransmitting();
5437         }
5438     }
5439 
5440     /** DpdIkeLocalInfo initiates a dead peer detection for IKE Session. */
5441     class DpdIkeLocalInfo extends DeleteBase {
5442         private Retransmitter mRetransmitter;
5443 
5444         @Override
enterState()5445         public void enterState() {
5446             mRetransmitter =
5447                     new EncryptedRetransmitter(
5448                             buildEncryptedInformationalMessage(
5449                                     new IkeInformationalPayload[0],
5450                                     false /*isResp*/,
5451                                     mCurrentIkeSaRecord.getLocalRequestMessageId()));
5452         }
5453 
5454         @Override
triggerRetransmit()5455         protected void triggerRetransmit() {
5456             mRetransmitter.retransmit();
5457         }
5458 
5459         @Override
handleRequestIkeMessage( IkeMessage ikeMessage, int ikeExchangeSubType, Message message)5460         protected void handleRequestIkeMessage(
5461                 IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
5462             switch (ikeExchangeSubType) {
5463                 case IKE_EXCHANGE_SUBTYPE_GENERIC_INFO:
5464                     handleGenericInfoRequest(ikeMessage);
5465                     return;
5466                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
5467                     // Reply and close IKE
5468                     handleDeleteSessionRequest(ikeMessage);
5469                     return;
5470                 default:
5471                     // Reply and stay in current state
5472                     buildAndSendErrorNotificationResponse(
5473                             mCurrentIkeSaRecord,
5474                             ikeMessage.ikeHeader.messageId,
5475                             ERROR_TYPE_TEMPORARY_FAILURE);
5476                     return;
5477             }
5478         }
5479 
5480         @Override
handleResponseIkeMessage(IkeMessage ikeMessage)5481         protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
5482             // DPD response usually contains no payload. But since there is not any requirement of
5483             // it, payload validation will be skipped.
5484             if (ikeMessage.ikeHeader.exchangeType == IkeHeader.EXCHANGE_TYPE_INFORMATIONAL) {
5485                 transitionTo(mIdle);
5486                 return;
5487             }
5488 
5489             handleResponseGenericProcessError(
5490                     mCurrentIkeSaRecord,
5491                     new InvalidSyntaxException(
5492                             "Invalid exchange type; expected INFORMATIONAL, but got: "
5493                                     + ikeMessage.ikeHeader.exchangeType));
5494         }
5495 
5496         @Override
handleResponseGenericProcessError( IkeSaRecord ikeSaRecord, InvalidSyntaxException exception)5497         protected void handleResponseGenericProcessError(
5498                 IkeSaRecord ikeSaRecord, InvalidSyntaxException exception) {
5499             loge("Invalid syntax on IKE DPD response.", exception);
5500             handleIkeFatalError(exception);
5501 
5502             // #exitState will be called when StateMachine quits
5503             quitSessionNow();
5504         }
5505 
5506         @Override
exitState()5507         public void exitState() {
5508             mRetransmitter.stopRetransmitting();
5509         }
5510     }
5511 
5512     /**
5513      * MobikeLocalInfo handles mobility event for the IKE Session.
5514      *
5515      * <p>When MOBIKE is supported by both sides, MobikeLocalInfo will initiate an
5516      * UPDATE_SA_ADDRESSES exchange for the IKE Session.
5517      */
5518     class MobikeLocalInfo extends DeleteBase {
5519         private Retransmitter mRetransmitter;
5520 
5521         @Override
enterState()5522         public void enterState() {
5523             if (!mEnabledExtensions.contains(EXTENSION_TYPE_MOBIKE)) {
5524                 logd(
5525                         "Non-MOBIKE mobility event: Server does not send"
5526                             + " NOTIFY_TYPE_MOBIKE_SUPPORTED. Skip UPDATE_SA_ADDRESSES exchange");
5527                 migrateAllChildSAs(false /* mobikeEnabled */);
5528                 notifyConnectionInfoChanged();
5529                 transitionTo(mIdle);
5530                 return;
5531             }
5532 
5533             logd("RFC4555 MOBIKE mobility event: Perform UPDATE_SA_ADDRESSES exchange");
5534             mRetransmitter = new EncryptedRetransmitter(buildUpdateSaAddressesReq());
5535         }
5536 
needNatDetection()5537         private boolean needNatDetection() {
5538             if (mIkeConnectionCtrl.getRemoteAddress() instanceof Inet4Address) {
5539                 // Add NAT_DETECTION payloads when it is unknown if server supports NAT-T or not, or
5540                 // it is known that server supports NAT-T.
5541                 return mIkeConnectionCtrl.getNatStatus() == NAT_TRAVERSAL_SUPPORT_NOT_CHECKED
5542                         || mIkeConnectionCtrl.getNatStatus() != NAT_TRAVERSAL_UNSUPPORTED;
5543             } else {
5544                 // Add NAT_DETECTION payloads only when a NAT has been detected previously. This is
5545                 // mainly for updating the previous NAT detection result, so that if IKE Session
5546                 // migrates from a v4 NAT environment to a v6 non-NAT environment, both sides can
5547                 // switch to use non-encap ESP SA. This is especially beneficial for implementations
5548                 // that do not support Ipv6 NAT-T.
5549                 return mIkeConnectionCtrl.getNatStatus() == NAT_DETECTED;
5550             }
5551         }
5552 
buildUpdateSaAddressesReq()5553         private IkeMessage buildUpdateSaAddressesReq() {
5554             // Generics required for addNatDetectionPayloadsToList that takes List<IkePayload> and
5555             // buildEncryptedInformationalMessage that takes InformationalPayload[].
5556             List<? super IkeInformationalPayload> payloadList = new ArrayList<>();
5557             payloadList.add(new IkeNotifyPayload(NOTIFY_TYPE_UPDATE_SA_ADDRESSES));
5558 
5559             if (needNatDetection()) {
5560                 addNatDetectionPayloadsToList(
5561                         (List<IkePayload>) payloadList,
5562                         mIkeConnectionCtrl.getLocalAddress(),
5563                         mIkeConnectionCtrl.getRemoteAddress(),
5564                         mIkeConnectionCtrl.getLocalPort(),
5565                         mIkeConnectionCtrl.getRemotePort(),
5566                         mCurrentIkeSaRecord.getInitiatorSpi(),
5567                         mCurrentIkeSaRecord.getResponderSpi(),
5568                         needEnableForceUdpEncap());
5569             }
5570 
5571             return buildEncryptedInformationalMessage(
5572                     mCurrentIkeSaRecord,
5573                     payloadList.toArray(new IkeInformationalPayload[payloadList.size()]),
5574                     false /* isResp */,
5575                     mCurrentIkeSaRecord.getLocalRequestMessageId());
5576         }
5577 
5578         @Override
triggerRetransmit()5579         protected void triggerRetransmit() {
5580             mRetransmitter.retransmit();
5581         }
5582 
5583         @Override
exitState()5584         public void exitState() {
5585             super.exitState();
5586 
5587             if (mRetransmitter != null) {
5588                 mRetransmitter.stopRetransmitting();
5589             }
5590         }
5591 
5592         @Override
handleRequestIkeMessage( IkeMessage msg, int ikeExchangeSubType, Message message)5593         public void handleRequestIkeMessage(
5594                 IkeMessage msg, int ikeExchangeSubType, Message message) {
5595             switch (ikeExchangeSubType) {
5596                 case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
5597                     handleDeleteSessionRequest(msg);
5598                     break;
5599 
5600                 default:
5601                     // Send a temporary failure for all non-DELETE_IKE requests
5602                     buildAndSendErrorNotificationResponse(
5603                             mCurrentIkeSaRecord,
5604                             msg.ikeHeader.messageId,
5605                             ERROR_TYPE_TEMPORARY_FAILURE);
5606             }
5607         }
5608 
5609         // Only called during RFC4555 MOBIKE mobility event
5610         @Override
handleResponseIkeMessage(IkeMessage resp)5611         public void handleResponseIkeMessage(IkeMessage resp) {
5612             mRetransmitter.stopRetransmitting();
5613 
5614             try {
5615                 validateResp(resp);
5616 
5617                 migrateAllChildSAs(true /* mobikeEnabled */);
5618                 notifyConnectionInfoChanged();
5619                 transitionTo(mIdle);
5620             } catch (IkeException | IOException e) {
5621                 handleIkeFatalError(e);
5622             }
5623         }
5624 
validateResp(IkeMessage resp)5625         private void validateResp(IkeMessage resp) throws IkeException, IOException {
5626             if (resp.ikeHeader.exchangeType != IkeHeader.EXCHANGE_TYPE_INFORMATIONAL) {
5627                 throw new InvalidSyntaxException(
5628                         "Invalid exchange type; expected INFORMATIONAL, but got: "
5629                                 + resp.ikeHeader.exchangeType);
5630             }
5631 
5632             List<IkeNotifyPayload> natSourcePayloads = new ArrayList<>();
5633             IkeNotifyPayload natDestPayload = null;
5634 
5635             for (IkePayload payload : resp.ikePayloadList) {
5636                 switch (payload.payloadType) {
5637                     case PAYLOAD_TYPE_NOTIFY:
5638                         IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
5639                         if (notifyPayload.isErrorNotify()) {
5640                             // TODO(b/): handle UNACCEPTABLE_ADDRESSES payload
5641                             throw notifyPayload.validateAndBuildIkeException();
5642                         }
5643 
5644                         switch (notifyPayload.notifyType) {
5645                             case NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP:
5646                                 natSourcePayloads.add(notifyPayload);
5647                                 break;
5648                             case NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP:
5649                                 if (natDestPayload != null) {
5650                                     throw new InvalidSyntaxException(
5651                                             "More than one"
5652                                                     + " NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP"
5653                                                     + " found");
5654                                 }
5655                                 natDestPayload = notifyPayload;
5656                                 break;
5657                             default:
5658                                 // Unknown and unexpected status notifications are ignored as per
5659                                 // RFC7296.
5660                                 logw(
5661                                         "Received unknown or unexpected status notifications with"
5662                                                 + " notify type: "
5663                                                 + notifyPayload.notifyType);
5664                         }
5665 
5666                         break;
5667                     default:
5668                         logw("Unexpected payload types found: " + payload.payloadType);
5669                 }
5670             }
5671 
5672             if (mRetransmitter.getMessage().hasNotifyPayload(NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP)) {
5673                 handleNatDetection(resp, natSourcePayloads, natDestPayload);
5674             }
5675         }
5676 
5677         /** Handle NAT detection and switch socket if needed */
handleNatDetection( IkeMessage resp, List<IkeNotifyPayload> natSourcePayloads, IkeNotifyPayload natDestPayload)5678         private void handleNatDetection(
5679                 IkeMessage resp,
5680                 List<IkeNotifyPayload> natSourcePayloads,
5681                 IkeNotifyPayload natDestPayload)
5682                 throws IkeException {
5683             if (!didPeerIncludeNattDetectionPayloads(natSourcePayloads, natDestPayload)) {
5684                 // If this is first time that IKE client sends NAT_DETECTION payloads, mark that the
5685                 // server does not support NAT-T
5686                 if (mIkeConnectionCtrl.getNatStatus() == NAT_TRAVERSAL_SUPPORT_NOT_CHECKED) {
5687                     mIkeConnectionCtrl.markSeverNattUnsupported();
5688                 }
5689                 return;
5690             }
5691 
5692             boolean isNatDetected =
5693                     isLocalOrRemoteNatDetected(
5694                             resp.ikeHeader.ikeInitiatorSpi,
5695                             resp.ikeHeader.ikeResponderSpi,
5696                             natSourcePayloads,
5697                             natDestPayload);
5698             mIkeConnectionCtrl.handleNatDetectionResultInMobike(isNatDetected);
5699         }
5700 
migrateAllChildSAs(boolean mobikeEnabled)5701         private void migrateAllChildSAs(boolean mobikeEnabled) {
5702             final int command =
5703                     mobikeEnabled
5704                             ? CMD_LOCAL_REQUEST_MIGRATE_CHILD
5705                             : CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE;
5706 
5707             // Schedule MOBIKE for all Child Sessions
5708             for (int i = 0; i < mRemoteSpiToChildSessionMap.size(); i++) {
5709                 int remoteChildSpi = mRemoteSpiToChildSessionMap.keyAt(i);
5710                 sendMessage(
5711                         command,
5712                         mLocalRequestFactory.getChildLocalRequest(command, remoteChildSpi));
5713             }
5714         }
5715 
notifyConnectionInfoChanged()5716         private void notifyConnectionInfoChanged() {
5717             IkeSessionConnectionInfo connectionInfo =
5718                     mIkeConnectionCtrl.buildIkeSessionConnectionInfo();
5719             executeUserCallback(
5720                     () -> mIkeSessionCallback.onIkeSessionConnectionInfoChanged(connectionInfo));
5721         }
5722     }
5723 
addNatDetectionPayloadsToList( List<IkePayload> payloadList, InetAddress localAddr, InetAddress remoteAddr, int localPort, int remotePort, long initIkeSpi, long respIkeSpi, boolean isForceUdpEncapEnabled)5724     private static void addNatDetectionPayloadsToList(
5725             List<IkePayload> payloadList,
5726             InetAddress localAddr,
5727             InetAddress remoteAddr,
5728             int localPort,
5729             int remotePort,
5730             long initIkeSpi,
5731             long respIkeSpi,
5732             boolean isForceUdpEncapEnabled) {
5733         // Though RFC says Notify-NAT payload is "just after the Ni and Nr payloads (before
5734         // the optional CERTREQ payload)", it also says recipient MUST NOT reject " messages
5735         // in which the payloads were not in the "right" order" due to the lack of clarity
5736         // of the payload order
5737         InetAddress localAddressToUse = localAddr;
5738 
5739         if (isForceUdpEncapEnabled) {
5740             IkeManager.getIkeLog().d(TAG, " Faking NAT situation to enforce UDP encapsulation");
5741             localAddressToUse =
5742                     (remoteAddr instanceof Inet4Address)
5743                             ? FORCE_ENCAP_FAKE_LOCAL_ADDRESS_IPV4
5744                             : FORCE_ENCAP_FAKE_LOCAL_ADDRESS_IPV6;
5745         }
5746 
5747         IkeNotifyPayload natdSrcIp =
5748                 new IkeNotifyPayload(
5749                         NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP,
5750                         IkeNotifyPayload.generateNatDetectionData(
5751                                 initIkeSpi, respIkeSpi, localAddressToUse, localPort));
5752 
5753         IkeNotifyPayload natdDstIp =
5754                 new IkeNotifyPayload(
5755                         NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP,
5756                         IkeNotifyPayload.generateNatDetectionData(
5757                                 initIkeSpi, respIkeSpi, remoteAddr, remotePort));
5758 
5759         payloadList.add(natdSrcIp);
5760         payloadList.add(natdDstIp);
5761     }
5762 
5763     private static class IkeEapOutboundMsgWrapper {
5764         private final boolean serverAuthenticated;
5765         private final byte[] eapMsg;
5766 
IkeEapOutboundMsgWrapper(boolean serverAuthenticated, byte[] eapMsg)5767         public IkeEapOutboundMsgWrapper(boolean serverAuthenticated, byte[] eapMsg) {
5768             this.serverAuthenticated = serverAuthenticated;
5769             this.eapMsg = eapMsg;
5770         }
5771 
isServerAuthenticated()5772         public boolean isServerAuthenticated() {
5773             return serverAuthenticated;
5774         }
5775 
getEapMsg()5776         public byte[] getEapMsg() {
5777             return eapMsg;
5778         }
5779     }
5780     /**
5781      * Helper class to generate IKE SA creation payloads, in both request and response directions.
5782      */
5783     private static class CreateIkeSaHelper {
getIkeInitSaRequestPayloads( IkeSaProposal[] saProposals, int selectedDhGroup, long initIkeSpi, long respIkeSpi, InetAddress localAddr, InetAddress remoteAddr, int localPort, int remotePort, RandomnessFactory randomFactory, boolean isForceUdpEncapEnabled)5784         public static List<IkePayload> getIkeInitSaRequestPayloads(
5785                 IkeSaProposal[] saProposals,
5786                 int selectedDhGroup,
5787                 long initIkeSpi,
5788                 long respIkeSpi,
5789                 InetAddress localAddr,
5790                 InetAddress remoteAddr,
5791                 int localPort,
5792                 int remotePort,
5793                 RandomnessFactory randomFactory,
5794                 boolean isForceUdpEncapEnabled)
5795                 throws IOException {
5796             List<IkePayload> payloadList =
5797                     getCreateIkeSaPayloads(
5798                             selectedDhGroup,
5799                             IkeSaPayload.createInitialIkeSaPayload(saProposals),
5800                             randomFactory);
5801 
5802             if (remoteAddr instanceof Inet4Address) {
5803                 // TODO(b/184869678): support NAT detection for all cases
5804                 // UdpEncap for V6 is not supported in Android yet, so only send NAT Detection
5805                 // payloads when using IPv4 addresses
5806                 addNatDetectionPayloadsToList(
5807                         payloadList,
5808                         localAddr,
5809                         remoteAddr,
5810                         localPort,
5811                         remotePort,
5812                         initIkeSpi,
5813                         respIkeSpi,
5814                         isForceUdpEncapEnabled);
5815             }
5816 
5817             return payloadList;
5818         }
5819 
getRekeyIkeSaRequestPayloads( IkeSaProposal[] saProposals, IkeSpiGenerator ikeSpiGenerator, InetAddress localAddr, RandomnessFactory randomFactory)5820         public static List<IkePayload> getRekeyIkeSaRequestPayloads(
5821                 IkeSaProposal[] saProposals,
5822                 IkeSpiGenerator ikeSpiGenerator,
5823                 InetAddress localAddr,
5824                 RandomnessFactory randomFactory)
5825                 throws IOException {
5826             if (localAddr == null) {
5827                 throw new IllegalArgumentException("Local address was null for rekey");
5828             }
5829 
5830             // Guaranteed to have at least one SA Proposal, since the IKE session was set up
5831             // properly.
5832             int selectedDhGroup = saProposals[0].getDhGroupTransforms()[0].id;
5833 
5834             return getCreateIkeSaPayloads(
5835                     selectedDhGroup,
5836                     IkeSaPayload.createRekeyIkeSaRequestPayload(
5837                             saProposals, ikeSpiGenerator, localAddr),
5838                     randomFactory);
5839         }
5840 
getRekeyIkeSaResponsePayloads( byte respProposalNumber, IkeSaProposal saProposal, IkeSpiGenerator ikeSpiGenerator, InetAddress localAddr, RandomnessFactory randomFactory)5841         public static List<IkePayload> getRekeyIkeSaResponsePayloads(
5842                 byte respProposalNumber,
5843                 IkeSaProposal saProposal,
5844                 IkeSpiGenerator ikeSpiGenerator,
5845                 InetAddress localAddr,
5846                 RandomnessFactory randomFactory)
5847                 throws IOException {
5848             if (localAddr == null) {
5849                 throw new IllegalArgumentException("Local address was null for rekey");
5850             }
5851 
5852             int selectedDhGroup = saProposal.getDhGroupTransforms()[0].id;
5853 
5854             return getCreateIkeSaPayloads(
5855                     selectedDhGroup,
5856                     IkeSaPayload.createRekeyIkeSaResponsePayload(
5857                             respProposalNumber, saProposal, ikeSpiGenerator, localAddr),
5858                     randomFactory);
5859         }
5860 
5861         /**
5862          * Builds the initial or rekey IKE creation payloads.
5863          *
5864          * <p>Will return a non-empty list of IkePayloads, the first of which WILL be the SA payload
5865          */
getCreateIkeSaPayloads( int selectedDhGroup, IkeSaPayload saPayload, RandomnessFactory randomFactory)5866         private static List<IkePayload> getCreateIkeSaPayloads(
5867                 int selectedDhGroup, IkeSaPayload saPayload, RandomnessFactory randomFactory)
5868                 throws IOException {
5869             if (saPayload.proposalList.size() == 0) {
5870                 throw new IllegalArgumentException("Invalid SA proposal list - was empty");
5871             }
5872 
5873             List<IkePayload> payloadList = new ArrayList<>(3);
5874 
5875             // The old IKE spec RFC 4306 (section 2.5 and 2.6) requires the payload order in IKE
5876             // INIT to be SAi, KEi, Ni and allow responders to reject requests with wrong order.
5877             // Although starting from RFC 5996, the protocol removed the allowance for rejecting
5878             // messages in which the payloads were not in the "right" order, there are few responder
5879             // implementations are still following the old spec when handling IKE INIT request with
5880             // COOKIE payload. Thus IKE library should follow the payload order to be compatible
5881             // with older implementations.
5882             payloadList.add(saPayload);
5883 
5884             // SaPropoals.Builder guarantees that each SA proposal has at least one DH group.
5885             payloadList.add(IkeKePayload.createOutboundKePayload(selectedDhGroup, randomFactory));
5886 
5887             payloadList.add(new IkeNoncePayload(randomFactory));
5888 
5889             return payloadList;
5890         }
5891     }
5892 
5893     // This call will be only fired when mIkeConnectionCtrl.isMobilityEnabled() is true
5894     @Override
onUnderlyingNetworkUpdated()5895     public void onUnderlyingNetworkUpdated() {
5896         // TODO(b/172013873): restart transmission timeouts on IKE SAs after changing networks
5897         sendMessage(
5898                 CMD_LOCAL_REQUEST_MOBIKE,
5899                 mLocalRequestFactory.getIkeLocalRequest(CMD_LOCAL_REQUEST_MOBIKE));
5900     }
5901 
5902     @Override
onUnderlyingNetworkDied(Network network)5903     public void onUnderlyingNetworkDied(Network network) {
5904         if (mIkeConnectionCtrl.isMobilityEnabled()) {
5905             // Do not tear down the session because 1) callers might want to migrate the IKE Session
5906             // when another network is available; 2) the termination from IKE Session might be
5907             // racing with the termination call from the callers.
5908             executeUserCallback(
5909                     () -> mIkeSessionCallback.onError(new IkeNetworkLostException(network)));
5910         } else {
5911             ShimUtils.getInstance().onUnderlyingNetworkDiedWithoutMobility(this, network);
5912         }
5913     }
5914 
5915     @Override
onError(IkeException exception)5916     public void onError(IkeException exception) {
5917         handleIkeFatalError(exception);
5918     }
5919 
5920     @Override
onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePacketBytes)5921     public void onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePacketBytes) {
5922         sendMessage(CMD_RECEIVE_IKE_PACKET, new ReceivedIkePacket(ikeHeader, ikePacketBytes));
5923     }
5924 
5925     // Implementation of IIkeSessionStateMachineShim
5926     @Override
onNonFatalError(Exception e)5927     public void onNonFatalError(Exception e) {
5928         executeUserCallback(() -> mIkeSessionCallback.onError(wrapAsIkeException(e)));
5929     }
5930 
5931     @Override
onFatalError(Exception e)5932     public void onFatalError(Exception e) {
5933         handleIkeFatalError(e);
5934     }
5935 }
5936