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