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 android.net.ipsec.ike; 17 18 import android.annotation.NonNull; 19 import android.annotation.SuppressLint; 20 import android.annotation.SystemApi; 21 import android.content.Context; 22 import android.content.pm.PackageManager; 23 import android.net.IpSecManager; 24 import android.os.HandlerThread; 25 import android.os.Looper; 26 import android.util.CloseGuard; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.internal.net.ipsec.ike.IkeSessionStateMachine; 30 31 import java.util.concurrent.Executor; 32 33 /** 34 * This class represents an IKE Session management object that allows for keying and management of 35 * {@link IpSecTransform}s. 36 * 37 * <p>An IKE/Child Session represents an IKE/Child SA as well as its rekeyed successors. A Child 38 * Session is bounded by the lifecycle of the IKE Session under which it is set up. Closing an IKE 39 * Session implicitly closes any remaining Child Sessions under it. 40 * 41 * <p>An IKE procedure is one or multiple IKE message exchanges that are used to create, delete or 42 * rekey an IKE Session or Child Session. 43 * 44 * <p>This class provides methods for initiating IKE procedures, such as the Creation and Deletion 45 * of a Child Session, or the Deletion of the IKE session. All procedures (except for IKE deletion) 46 * will be initiated sequentially after IKE Session is set up. 47 * 48 * @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange Protocol 49 * Version 2 (IKEv2)</a> 50 * @hide 51 */ 52 @SystemApi 53 public final class IkeSession implements AutoCloseable { 54 private final CloseGuard mCloseGuard = new CloseGuard(); 55 private final Context mContext; 56 57 @VisibleForTesting final IkeSessionStateMachine mIkeSessionStateMachine; 58 59 /** 60 * Constructs a new IKE session. 61 * 62 * <p>This method will immediately return an instance of {@link IkeSession} and asynchronously 63 * initiate the setup procedure of {@link IkeSession} as well as its first Child Session. 64 * Callers will be notified of these two setup results via the callback arguments. 65 * 66 * <p>FEATURE_IPSEC_TUNNELS is required for setting up a tunnel mode Child SA. 67 * 68 * @param context a valid {@link Context} instance. 69 * @param ikeSessionParams the {@link IkeSessionParams} that contains a set of valid {@link 70 * IkeSession} configurations. 71 * @param firstChildSessionParams the {@link ChildSessionParams} that contains a set of valid 72 * configurations for the first Child Session. 73 * @param userCbExecutor the {@link Executor} upon which all callbacks will be posted. For 74 * security and consistency, the callbacks posted to this executor MUST be executed serially 75 * and in the order they were posted, as guaranteed by executors such as {@link 76 * ExecutorService.newSingleThreadExecutor()} 77 * @param ikeSessionCallback the {@link IkeSessionCallback} interface to notify callers of state 78 * changes within the {@link IkeSession}. 79 * @param firstChildSessionCallback the {@link ChildSessionCallback} interface to notify callers 80 * of state changes within the first Child Session. 81 * @return an instance of {@link IkeSession}. 82 */ IkeSession( @onNull Context context, @NonNull IkeSessionParams ikeSessionParams, @NonNull ChildSessionParams firstChildSessionParams, @NonNull Executor userCbExecutor, @NonNull IkeSessionCallback ikeSessionCallback, @NonNull ChildSessionCallback firstChildSessionCallback)83 public IkeSession( 84 @NonNull Context context, 85 @NonNull IkeSessionParams ikeSessionParams, 86 @NonNull ChildSessionParams firstChildSessionParams, 87 @NonNull Executor userCbExecutor, 88 @NonNull IkeSessionCallback ikeSessionCallback, 89 @NonNull ChildSessionCallback firstChildSessionCallback) { 90 this( 91 context, 92 (IpSecManager) context.getSystemService(Context.IPSEC_SERVICE), 93 ikeSessionParams, 94 firstChildSessionParams, 95 userCbExecutor, 96 ikeSessionCallback, 97 firstChildSessionCallback); 98 } 99 100 /** Package private */ 101 @VisibleForTesting IkeSession( Context context, IpSecManager ipSecManager, IkeSessionParams ikeSessionParams, ChildSessionParams firstChildSessionParams, Executor userCbExecutor, IkeSessionCallback ikeSessionCallback, ChildSessionCallback firstChildSessionCallback)102 IkeSession( 103 Context context, 104 IpSecManager ipSecManager, 105 IkeSessionParams ikeSessionParams, 106 ChildSessionParams firstChildSessionParams, 107 Executor userCbExecutor, 108 IkeSessionCallback ikeSessionCallback, 109 ChildSessionCallback firstChildSessionCallback) { 110 this( 111 IkeThreadHolder.IKE_WORKER_THREAD.getLooper(), 112 context, 113 ipSecManager, 114 ikeSessionParams, 115 firstChildSessionParams, 116 userCbExecutor, 117 ikeSessionCallback, 118 firstChildSessionCallback); 119 } 120 121 /** Package private */ 122 @VisibleForTesting IkeSession( Looper looper, Context context, IpSecManager ipSecManager, IkeSessionParams ikeSessionParams, ChildSessionParams firstChildSessionParams, Executor userCbExecutor, IkeSessionCallback ikeSessionCallback, ChildSessionCallback firstChildSessionCallback)123 IkeSession( 124 Looper looper, 125 Context context, 126 IpSecManager ipSecManager, 127 IkeSessionParams ikeSessionParams, 128 ChildSessionParams firstChildSessionParams, 129 Executor userCbExecutor, 130 IkeSessionCallback ikeSessionCallback, 131 ChildSessionCallback firstChildSessionCallback) { 132 mContext = context; 133 134 if (firstChildSessionParams instanceof TunnelModeChildSessionParams) { 135 checkTunnelFeatureOrThrow(mContext); 136 } 137 138 mIkeSessionStateMachine = 139 new IkeSessionStateMachine( 140 looper, 141 context, 142 ipSecManager, 143 ikeSessionParams, 144 firstChildSessionParams, 145 userCbExecutor, 146 ikeSessionCallback, 147 firstChildSessionCallback); 148 mIkeSessionStateMachine.openSession(); 149 150 mCloseGuard.open("open"); 151 } 152 153 /** @hide */ 154 @Override finalize()155 public void finalize() { 156 if (mCloseGuard != null) { 157 mCloseGuard.warnIfOpen(); 158 } 159 } 160 checkTunnelFeatureOrThrow(Context context)161 private void checkTunnelFeatureOrThrow(Context context) { 162 // TODO(b/157754168): Also check if OP_MANAGE_IPSEC_TUNNELS is granted when it is exposed 163 if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) { 164 throw new IllegalStateException( 165 "Cannot set up tunnel mode Child SA due to FEATURE_IPSEC_TUNNELS missing"); 166 } 167 } 168 169 /** Initialization-on-demand holder */ 170 private static class IkeThreadHolder { 171 static final HandlerThread IKE_WORKER_THREAD; 172 173 static { 174 IKE_WORKER_THREAD = new HandlerThread("IkeWorkerThread"); IKE_WORKER_THREAD.start()175 IKE_WORKER_THREAD.start(); 176 } 177 } 178 179 // TODO: b/133340675 Destroy the worker thread when there is no more alive {@link IkeSession}. 180 181 /** 182 * Request a new Child Session. 183 * 184 * <p>Users MUST provide a unique {@link ChildSessionCallback} instance for each new Child 185 * Session. 186 * 187 * <p>Upon setup, {@link ChildSessionCallback#onOpened(ChildSessionConfiguration)} will be 188 * fired. 189 * 190 * <p>FEATURE_IPSEC_TUNNELS is required for setting up a tunnel mode Child SA. 191 * 192 * @param childSessionParams the {@link ChildSessionParams} that contains the Child Session 193 * configurations to negotiate. 194 * @param childSessionCallback the {@link ChildSessionCallback} interface to notify users the 195 * state changes of the Child Session. It will be posted to the callback {@link Executor} of 196 * this {@link IkeSession}. 197 * @throws IllegalArgumentException if the ChildSessionCallback is already in use. 198 */ 199 // The childSessionCallback will be called on the same executor as was passed in the constructor 200 // for security reasons. 201 @SuppressLint("ExecutorRegistration") openChildSession( @onNull ChildSessionParams childSessionParams, @NonNull ChildSessionCallback childSessionCallback)202 public void openChildSession( 203 @NonNull ChildSessionParams childSessionParams, 204 @NonNull ChildSessionCallback childSessionCallback) { 205 if (childSessionParams instanceof TunnelModeChildSessionParams) { 206 checkTunnelFeatureOrThrow(mContext); 207 } 208 209 mIkeSessionStateMachine.openChildSession(childSessionParams, childSessionCallback); 210 } 211 212 /** 213 * Delete a Child Session. 214 * 215 * <p>Upon closure, {@link ChildSessionCallback#onClosed()} will be fired. 216 * 217 * @param childSessionCallback The {@link ChildSessionCallback} instance that uniquely identify 218 * the Child Session. 219 * @throws IllegalArgumentException if no Child Session found bound with this callback. 220 */ 221 // The childSessionCallback will be called on the same executor as was passed in the constructor 222 // for security reasons. 223 @SuppressLint("ExecutorRegistration") closeChildSession(@onNull ChildSessionCallback childSessionCallback)224 public void closeChildSession(@NonNull ChildSessionCallback childSessionCallback) { 225 mIkeSessionStateMachine.closeChildSession(childSessionCallback); 226 } 227 228 /** 229 * Close the IKE session gracefully. 230 * 231 * <p>Implements {@link AutoCloseable#close()} 232 * 233 * <p>Upon closure, {@link IkeSessionCallback#onClosed()} or {@link 234 * IkeSessionCallback#onClosedExceptionally()} will be fired. 235 * 236 * <p>Closing an IKE Session implicitly closes any remaining Child Sessions negotiated under it. 237 * Users SHOULD stop all outbound traffic that uses these Child Sessions({@link IpSecTransform} 238 * pairs) before calling this method. Otherwise IPsec packets will be dropped due to the lack of 239 * a valid {@link IpSecTransform}. 240 * 241 * <p>Closure of an IKE session will take priority over, and cancel other procedures waiting in 242 * the queue (but will wait for ongoing locally initiated procedures to complete). After sending 243 * the Delete request, the IKE library will wait until a Delete response is received or 244 * retransmission timeout occurs. 245 */ 246 @Override close()247 public void close() { 248 mCloseGuard.close(); 249 mIkeSessionStateMachine.closeSession(); 250 } 251 252 /** 253 * Terminate (forcibly close) the IKE session. 254 * 255 * <p>Upon closing, {@link IkeSessionCallback#onClosed()} will be fired. 256 * 257 * <p>Closing an IKE Session implicitly closes any remaining Child Sessions negotiated under it. 258 * Users SHOULD stop all outbound traffic that uses these Child Sessions({@link IpSecTransform} 259 * pairs) before calling this method. Otherwise IPsec packets will be dropped due to the lack of 260 * a valid {@link IpSecTransform}. 261 * 262 * <p>Forcible closure of an IKE session will take priority over, and cancel other procedures 263 * waiting in the queue. It will also interrupt any ongoing locally initiated procedure. 264 */ kill()265 public void kill() { 266 mCloseGuard.close(); 267 mIkeSessionStateMachine.killSession(); 268 } 269 } 270