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