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