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