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