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