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