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