blob: f2200cf1d2d65b3f27f84eecb3d6439de2f368c9 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.Context;
import android.net.IpSecManager;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.CloseGuard;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.ipsec.ike.IkeSessionStateMachine;
import java.util.concurrent.Executor;
/**
* This class represents an IKE Session management object that allows for keying and management of
* {@link IpSecTransform}s.
*
* <p>An IKE/Child Session represents an IKE/Child SA as well as its rekeyed successors. A Child
* Session is bounded by the lifecycle of the IKE Session under which it is set up. Closing an IKE
* Session implicitly closes any remaining Child Sessions under it.
*
* <p>An IKE procedure is one or multiple IKE message exchanges that are used to create, delete or
* rekey an IKE Session or Child Session.
*
* <p>This class provides methods for initiating IKE procedures, such as the Creation and Deletion
* of a Child Session, or the Deletion of the IKE session. All procedures (except for IKE deletion)
* will be initiated sequentially after IKE Session is set up.
*
* @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange Protocol
* Version 2 (IKEv2)</a>
* @hide
*/
@SystemApi
public final class IkeSession implements AutoCloseable {
private final CloseGuard mCloseGuard = new CloseGuard();
@VisibleForTesting final IkeSessionStateMachine mIkeSessionStateMachine;
/**
* Constructs a new IKE session.
*
* <p>This method will immediately return an instance of {@link IkeSession} and asynchronously
* initiate the setup procedure of {@link IkeSession} as well as its first Child Session.
* Callers will be notified of these two setup results via the callback arguments.
*
* @param context a valid {@link Context} instance.
* @param ikeSessionParams the {@link IkeSessionParams} that contains a set of valid {@link
* IkeSession} configurations.
* @param firstChildSessionParams the {@link ChildSessionParams} that contains a set of valid
* configurations for the first Child Session.
* @param userCbExecutor the {@link Executor} upon which all callbacks will be posted. For
* security and consistency, the callbacks posted to this executor MUST be executed serially
* and in the order they were posted, as guaranteed by executors such as {@link
* ExecutorService.newSingleThreadExecutor()}
* @param ikeSessionCallback the {@link IkeSessionCallback} interface to notify callers of state
* changes within the {@link IkeSession}.
* @param firstChildSessionCallback the {@link ChildSessionCallback} interface to notify callers
* of state changes within the first Child Session.
* @return an instance of {@link IkeSession}.
*/
public IkeSession(
@NonNull Context context,
@NonNull IkeSessionParams ikeSessionParams,
@NonNull ChildSessionParams firstChildSessionParams,
@NonNull Executor userCbExecutor,
@NonNull IkeSessionCallback ikeSessionCallback,
@NonNull ChildSessionCallback firstChildSessionCallback) {
this(
context,
(IpSecManager) context.getSystemService(Context.IPSEC_SERVICE),
ikeSessionParams,
firstChildSessionParams,
userCbExecutor,
ikeSessionCallback,
firstChildSessionCallback);
}
/** Package private */
@VisibleForTesting
IkeSession(
Context context,
IpSecManager ipSecManager,
IkeSessionParams ikeSessionParams,
ChildSessionParams firstChildSessionParams,
Executor userCbExecutor,
IkeSessionCallback ikeSessionCallback,
ChildSessionCallback firstChildSessionCallback) {
this(
IkeThreadHolder.IKE_WORKER_THREAD.getLooper(),
context,
ipSecManager,
ikeSessionParams,
firstChildSessionParams,
userCbExecutor,
ikeSessionCallback,
firstChildSessionCallback);
}
/** Package private */
@VisibleForTesting
IkeSession(
Looper looper,
Context context,
IpSecManager ipSecManager,
IkeSessionParams ikeSessionParams,
ChildSessionParams firstChildSessionParams,
Executor userCbExecutor,
IkeSessionCallback ikeSessionCallback,
ChildSessionCallback firstChildSessionCallback) {
mIkeSessionStateMachine =
new IkeSessionStateMachine(
looper,
context,
ipSecManager,
ikeSessionParams,
firstChildSessionParams,
userCbExecutor,
ikeSessionCallback,
firstChildSessionCallback);
mIkeSessionStateMachine.openSession();
mCloseGuard.open("open");
}
/** @hide */
@Override
public void finalize() {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
}
}
/** Initialization-on-demand holder */
private static class IkeThreadHolder {
static final HandlerThread IKE_WORKER_THREAD;
static {
IKE_WORKER_THREAD = new HandlerThread("IkeWorkerThread");
IKE_WORKER_THREAD.start();
}
}
// TODO: b/133340675 Destroy the worker thread when there is no more alive {@link IkeSession}.
/**
* Request a new Child Session.
*
* <p>Users MUST provide a unique {@link ChildSessionCallback} instance for each new Child
* Session.
*
* <p>Upon setup, {@link ChildSessionCallback#onOpened(ChildSessionConfiguration)} will be
* fired.
*
* @param childSessionParams the {@link ChildSessionParams} that contains the Child Session
* configurations to negotiate.
* @param childSessionCallback the {@link ChildSessionCallback} interface to notify users the
* state changes of the Child Session. It will be posted to the callback {@link Executor} of
* this {@link IkeSession}.
* @throws IllegalArgumentException if the ChildSessionCallback is already in use.
*/
// The childSessionCallback will be called on the same executor as was passed in the constructor
// for security reasons.
@SuppressLint("ExecutorRegistration")
public void openChildSession(
@NonNull ChildSessionParams childSessionParams,
@NonNull ChildSessionCallback childSessionCallback) {
mIkeSessionStateMachine.openChildSession(childSessionParams, childSessionCallback);
}
/**
* Delete a Child Session.
*
* <p>Upon closure, {@link ChildSessionCallback#onClosed()} will be fired.
*
* @param childSessionCallback The {@link ChildSessionCallback} instance that uniquely identify
* the Child Session.
* @throws IllegalArgumentException if no Child Session found bound with this callback.
*/
// The childSessionCallback will be called on the same executor as was passed in the constructor
// for security reasons.
@SuppressLint("ExecutorRegistration")
public void closeChildSession(@NonNull ChildSessionCallback childSessionCallback) {
mIkeSessionStateMachine.closeChildSession(childSessionCallback);
}
/**
* Close the IKE session gracefully.
*
* <p>Implements {@link AutoCloseable#close()}
*
* <p>Upon closure, {@link IkeSessionCallback#onClosed()} or {@link
* IkeSessionCallback#onClosedExceptionally()} will be fired.
*
* <p>Closing an IKE Session implicitly closes any remaining Child Sessions negotiated under it.
* Users SHOULD stop all outbound traffic that uses these Child Sessions({@link IpSecTransform}
* pairs) before calling this method. Otherwise IPsec packets will be dropped due to the lack of
* a valid {@link IpSecTransform}.
*
* <p>Closure of an IKE session will take priority over, and cancel other procedures waiting in
* the queue (but will wait for ongoing locally initiated procedures to complete). After sending
* the Delete request, the IKE library will wait until a Delete response is received or
* retransmission timeout occurs.
*/
@Override
public void close() {
mCloseGuard.close();
mIkeSessionStateMachine.closeSession();
}
/**
* Terminate (forcibly close) the IKE session.
*
* <p>Upon closing, {@link IkeSessionCallback#onClosed()} will be fired.
*
* <p>Closing an IKE Session implicitly closes any remaining Child Sessions negotiated under it.
* Users SHOULD stop all outbound traffic that uses these Child Sessions({@link IpSecTransform}
* pairs) before calling this method. Otherwise IPsec packets will be dropped due to the lack of
* a valid {@link IpSecTransform}.
*
* <p>Forcible closure of an IKE session will take priority over, and cancel other procedures
* waiting in the queue. It will also interrupt any ongoing locally initiated procedure.
*/
public void kill() {
mCloseGuard.close();
mIkeSessionStateMachine.killSession();
}
}