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