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