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