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