blob: 9ccdbe2b1bdc9ad3b35b4677e66ac6edec1eedf0 [file] [log] [blame]
Nathan Harold330e1082017-01-12 18:38:57 -08001/*
2 * Copyright (C) 2017 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 */
16package android.net;
17
Nathan Harold93962f32017-03-07 13:23:36 -080018import static android.net.IpSecManager.INVALID_RESOURCE_ID;
Nathan Harold93962f32017-03-07 13:23:36 -080019
Nathan Haroldc43e89f2017-12-06 19:12:28 -080020import static com.android.internal.util.Preconditions.checkNotNull;
21
Nathan Harold330e1082017-01-12 18:38:57 -080022import android.annotation.IntDef;
Nathan Harold93962f32017-03-07 13:23:36 -080023import android.annotation.NonNull;
Nathan Harold330e1082017-01-12 18:38:57 -080024import android.annotation.SystemApi;
25import android.content.Context;
Nathan Harold93962f32017-03-07 13:23:36 -080026import android.os.Binder;
Nathan Haroldc43e89f2017-12-06 19:12:28 -080027import android.os.Handler;
Nathan Harold93962f32017-03-07 13:23:36 -080028import android.os.IBinder;
29import android.os.RemoteException;
30import android.os.ServiceManager;
Nathan Harold330e1082017-01-12 18:38:57 -080031import android.util.Log;
Nathan Haroldd999d222017-09-11 19:53:33 -070032
ludi1a06aa72017-05-12 09:15:00 -070033import com.android.internal.annotations.VisibleForTesting;
Nathan Harold93962f32017-03-07 13:23:36 -080034import com.android.internal.util.Preconditions;
Nathan Haroldd999d222017-09-11 19:53:33 -070035
Nathan Harold330e1082017-01-12 18:38:57 -080036import dalvik.system.CloseGuard;
Nathan Haroldd999d222017-09-11 19:53:33 -070037
Nathan Harold330e1082017-01-12 18:38:57 -080038import java.io.IOException;
39import java.lang.annotation.Retention;
40import java.lang.annotation.RetentionPolicy;
41import java.net.InetAddress;
42
43/**
Nathan Harolda2523312018-01-05 19:25:13 -080044 * This class represents a transform, which roughly corresponds to an IPsec Security Association.
Nathan Harold330e1082017-01-12 18:38:57 -080045 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -070046 * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform}
Nathan Harolda2523312018-01-05 19:25:13 -080047 * object encapsulates the properties and state of an IPsec security association. That includes,
48 * but is not limited to, algorithm choice, key material, and allocated system resources.
Nathan Harold330e1082017-01-12 18:38:57 -080049 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -070050 * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
Jonathan Basseri5fb92902017-11-16 10:58:01 -080051 * Internet Protocol</a>
Nathan Harold330e1082017-01-12 18:38:57 -080052 */
53public final class IpSecTransform implements AutoCloseable {
54 private static final String TAG = "IpSecTransform";
55
Nathan Harold330e1082017-01-12 18:38:57 -080056 /** @hide */
Nathan Harolda10003d2017-08-23 13:46:33 -070057 public static final int MODE_TRANSPORT = 0;
Nathan Harold330e1082017-01-12 18:38:57 -080058
59 /** @hide */
Nathan Harolda10003d2017-08-23 13:46:33 -070060 public static final int MODE_TUNNEL = 1;
Nathan Harold330e1082017-01-12 18:38:57 -080061
62 /** @hide */
63 public static final int ENCAP_NONE = 0;
64
65 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070066 * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP
67 * header and payload. This prevents traffic from being interpreted as ESP or IKEv2.
Nathan Harold330e1082017-01-12 18:38:57 -080068 *
69 * @hide
70 */
Nathan Harold8dc1fd02017-04-04 19:37:48 -070071 public static final int ENCAP_ESPINUDP_NON_IKE = 1;
72
73 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070074 * IPsec traffic will be encapsulated within UDP as per
75 * <a href="https://tools.ietf.org/html/rfc3948">RFC 3498</a>.
Nathan Harold8dc1fd02017-04-04 19:37:48 -070076 *
77 * @hide
78 */
79 public static final int ENCAP_ESPINUDP = 2;
Nathan Harold330e1082017-01-12 18:38:57 -080080
81 /** @hide */
Nathan Harold8dc1fd02017-04-04 19:37:48 -070082 @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NON_IKE})
Nathan Harold330e1082017-01-12 18:38:57 -080083 @Retention(RetentionPolicy.SOURCE)
84 public @interface EncapType {}
85
Nathan Harold330e1082017-01-12 18:38:57 -080086 private IpSecTransform(Context context, IpSecConfig config) {
87 mContext = context;
88 mConfig = config;
Nathan Harold93962f32017-03-07 13:23:36 -080089 mResourceId = INVALID_RESOURCE_ID;
90 }
91
92 private IIpSecService getIpSecService() {
93 IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE);
94 if (b == null) {
95 throw new RemoteException("Failed to connect to IpSecService")
96 .rethrowAsRuntimeException();
97 }
98
99 return IIpSecService.Stub.asInterface(b);
100 }
101
Nathan Harolda10003d2017-08-23 13:46:33 -0700102 /**
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800103 * Checks the result status and throws an appropriate exception if the status is not Status.OK.
Nathan Harolda10003d2017-08-23 13:46:33 -0700104 */
105 private void checkResultStatus(int status)
Nathan Harold93962f32017-03-07 13:23:36 -0800106 throws IOException, IpSecManager.ResourceUnavailableException,
107 IpSecManager.SpiUnavailableException {
108 switch (status) {
109 case IpSecManager.Status.OK:
110 return;
111 // TODO: Pass Error string back from bundle so that errors can be more specific
112 case IpSecManager.Status.RESOURCE_UNAVAILABLE:
113 throw new IpSecManager.ResourceUnavailableException(
114 "Failed to allocate a new IpSecTransform");
115 case IpSecManager.Status.SPI_UNAVAILABLE:
116 Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved");
117 // Fall through
118 default:
119 throw new IllegalStateException(
120 "Failed to Create a Transform with status code " + status);
121 }
Nathan Harold330e1082017-01-12 18:38:57 -0800122 }
123
124 private IpSecTransform activate()
125 throws IOException, IpSecManager.ResourceUnavailableException,
126 IpSecManager.SpiUnavailableException {
Nathan Harold330e1082017-01-12 18:38:57 -0800127 synchronized (this) {
Nathan Harold93962f32017-03-07 13:23:36 -0800128 try {
129 IIpSecService svc = getIpSecService();
Benedict Wongf33f03132018-01-18 14:38:16 -0800130 IpSecTransformResponse result = svc.createTransform(mConfig, new Binder());
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700131 int status = result.status;
Nathan Harolda10003d2017-08-23 13:46:33 -0700132 checkResultStatus(status);
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700133 mResourceId = result.resourceId;
Nathan Harold93962f32017-03-07 13:23:36 -0800134 Log.d(TAG, "Added Transform with Id " + mResourceId);
135 mCloseGuard.open("build");
136 } catch (RemoteException e) {
137 throw e.rethrowAsRuntimeException();
Nathan Harold330e1082017-01-12 18:38:57 -0800138 }
Nathan Harold330e1082017-01-12 18:38:57 -0800139 }
Nathan Harold330e1082017-01-12 18:38:57 -0800140
141 return this;
142 }
143
144 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700145 * Deactivate this {@code IpSecTransform} and free allocated resources.
Nathan Harold330e1082017-01-12 18:38:57 -0800146 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700147 * <p>Deactivating a transform while it is still applied to a socket will result in errors on
148 * that socket. Make sure to remove transforms by calling {@link
Nathan Harolda2523312018-01-05 19:25:13 -0800149 * IpSecManager#removeTransportModeTransforms}. Note, removing an {@code IpSecTransform} from a
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700150 * socket will not deactivate it (because one transform may be applied to multiple sockets).
151 *
152 * <p>It is safe to call this method on a transform that has already been deactivated.
Nathan Harold330e1082017-01-12 18:38:57 -0800153 */
154 public void close() {
Nathan Harold93962f32017-03-07 13:23:36 -0800155 Log.d(TAG, "Removing Transform with Id " + mResourceId);
Nathan Harold330e1082017-01-12 18:38:57 -0800156
157 // Always safe to attempt cleanup
Nathan Harold93962f32017-03-07 13:23:36 -0800158 if (mResourceId == INVALID_RESOURCE_ID) {
159 mCloseGuard.close();
Nathan Harold330e1082017-01-12 18:38:57 -0800160 return;
161 }
Nathan Harold93962f32017-03-07 13:23:36 -0800162 try {
Nathan Harold93962f32017-03-07 13:23:36 -0800163 IIpSecService svc = getIpSecService();
Benedict Wongf33f03132018-01-18 14:38:16 -0800164 svc.deleteTransform(mResourceId);
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800165 stopNattKeepalive();
Nathan Harold93962f32017-03-07 13:23:36 -0800166 } catch (RemoteException e) {
167 throw e.rethrowAsRuntimeException();
168 } finally {
169 mResourceId = INVALID_RESOURCE_ID;
170 mCloseGuard.close();
171 }
Nathan Harold330e1082017-01-12 18:38:57 -0800172 }
173
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700174 /** Check that the transform was closed properly. */
Nathan Harold330e1082017-01-12 18:38:57 -0800175 @Override
176 protected void finalize() throws Throwable {
177 if (mCloseGuard != null) {
178 mCloseGuard.warnIfOpen();
179 }
180 close();
181 }
182
183 /* Package */
184 IpSecConfig getConfig() {
185 return mConfig;
186 }
187
188 private final IpSecConfig mConfig;
Nathan Harold93962f32017-03-07 13:23:36 -0800189 private int mResourceId;
Nathan Harold330e1082017-01-12 18:38:57 -0800190 private final Context mContext;
191 private final CloseGuard mCloseGuard = CloseGuard.get();
192 private ConnectivityManager.PacketKeepalive mKeepalive;
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800193 private Handler mCallbackHandler;
194 private final ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback =
Nathan Harold330e1082017-01-12 18:38:57 -0800195 new ConnectivityManager.PacketKeepaliveCallback() {
196
197 @Override
198 public void onStarted() {
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800199 synchronized (this) {
200 mCallbackHandler.post(() -> mUserKeepaliveCallback.onStarted());
Nathan Harold330e1082017-01-12 18:38:57 -0800201 }
202 }
203
204 @Override
205 public void onStopped() {
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800206 synchronized (this) {
207 mKeepalive = null;
208 mCallbackHandler.post(() -> mUserKeepaliveCallback.onStopped());
Nathan Harold330e1082017-01-12 18:38:57 -0800209 }
210 }
211
212 @Override
213 public void onError(int error) {
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800214 synchronized (this) {
215 mKeepalive = null;
216 mCallbackHandler.post(() -> mUserKeepaliveCallback.onError(error));
Nathan Harold330e1082017-01-12 18:38:57 -0800217 }
218 }
219 };
220
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800221 private NattKeepaliveCallback mUserKeepaliveCallback;
Nathan Harold330e1082017-01-12 18:38:57 -0800222
Nathan Harolda10003d2017-08-23 13:46:33 -0700223 /** @hide */
224 @VisibleForTesting
225 public int getResourceId() {
Nathan Harold93962f32017-03-07 13:23:36 -0800226 return mResourceId;
227 }
228
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800229 /**
230 * A callback class to provide status information regarding a NAT-T keepalive session
231 *
232 * <p>Use this callback to receive status information regarding a NAT-T keepalive session
233 * by registering it when calling {@link #startNattKeepalive}.
234 *
235 * @hide
236 */
237 @SystemApi
238 public static class NattKeepaliveCallback {
239 /** The specified {@code Network} is not connected. */
240 public static final int ERROR_INVALID_NETWORK = 1;
241 /** The hardware does not support this request. */
242 public static final int ERROR_HARDWARE_UNSUPPORTED = 2;
243 /** The hardware returned an error. */
244 public static final int ERROR_HARDWARE_ERROR = 3;
245
246 /** The requested keepalive was successfully started. */
247 public void onStarted() {}
248 /** The keepalive was successfully stopped. */
249 public void onStopped() {}
250 /** An error occurred. */
251 public void onError(int error) {}
252 }
253
254 /**
255 * Start a NAT-T keepalive session for the current transform.
256 *
257 * For a transform that is using UDP encapsulated IPv4, NAT-T offloading provides
258 * a power efficient mechanism of sending NAT-T packets at a specified interval.
259 *
260 * @param userCallback a {@link #NattKeepaliveCallback} to receive asynchronous status
261 * information about the requested NAT-T keepalive session.
262 * @param intervalSeconds the interval between NAT-T keepalives being sent. The
263 * the allowed range is between 20 and 3600 seconds.
264 * @param handler a handler on which to post callbacks when received.
265 *
266 * @hide
267 */
268 @SystemApi
269 public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback,
270 int intervalSeconds, @NonNull Handler handler) throws IOException {
271 checkNotNull(userCallback);
272 if (intervalSeconds < 20 || intervalSeconds > 3600) {
273 throw new IllegalArgumentException("Invalid NAT-T keepalive interval");
274 }
275 checkNotNull(handler);
276 if (mResourceId == INVALID_RESOURCE_ID) {
277 throw new IllegalStateException(
278 "Packet keepalive cannot be started for an inactive transform");
279 }
280
281 synchronized (mKeepaliveCallback) {
282 if (mKeepaliveCallback != null) {
283 throw new IllegalStateException("Keepalive already active");
284 }
285
286 mUserKeepaliveCallback = userCallback;
287 ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
288 Context.CONNECTIVITY_SERVICE);
289 mKeepalive = cm.startNattKeepalive(
290 mConfig.getNetwork(), intervalSeconds, mKeepaliveCallback,
291 NetworkUtils.numericToInetAddress(mConfig.getSourceAddress()),
292 4500, // FIXME urgently, we need to get the port number from the Encap socket
293 NetworkUtils.numericToInetAddress(mConfig.getDestinationAddress()));
294 mCallbackHandler = handler;
295 }
296 }
297
298 /**
299 * Stop an ongoing NAT-T keepalive session.
300 *
301 * Calling this API will request that an ongoing NAT-T keepalive session be terminated.
302 * If this API is not called when a Transform is closed, the underlying NAT-T session will
303 * be terminated automatically.
304 *
305 * @hide
306 */
307 @SystemApi
308 public void stopNattKeepalive() {
309 synchronized (mKeepaliveCallback) {
310 if (mKeepalive == null) {
311 Log.e(TAG, "No active keepalive to stop");
312 return;
313 }
314 mKeepalive.stop();
315 }
Nathan Harold330e1082017-01-12 18:38:57 -0800316 }
317
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800318 /** This class is used to build {@link IpSecTransform} objects. */
Nathan Harold330e1082017-01-12 18:38:57 -0800319 public static class Builder {
320 private Context mContext;
321 private IpSecConfig mConfig;
322
323 /**
Nathan Harolda2523312018-01-05 19:25:13 -0800324 * Set the encryption algorithm.
Nathan Harold330e1082017-01-12 18:38:57 -0800325 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700326 * <p>Encryption is mutually exclusive with authenticated encryption.
Benedict Wong0febe5e2017-08-22 21:42:33 -0700327 *
Nathan Harold330e1082017-01-12 18:38:57 -0800328 * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
329 */
Nathan Harolda2523312018-01-05 19:25:13 -0800330 public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700331 // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
Nathan Harolda2523312018-01-05 19:25:13 -0800332 Preconditions.checkNotNull(algo);
333 mConfig.setEncryption(algo);
Nathan Harold330e1082017-01-12 18:38:57 -0800334 return this;
335 }
336
337 /**
Nathan Harolda2523312018-01-05 19:25:13 -0800338 * Set the authentication (integrity) algorithm.
Nathan Harold330e1082017-01-12 18:38:57 -0800339 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700340 * <p>Authentication is mutually exclusive with authenticated encryption.
Benedict Wong0febe5e2017-08-22 21:42:33 -0700341 *
Nathan Harold330e1082017-01-12 18:38:57 -0800342 * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
343 */
Nathan Harolda2523312018-01-05 19:25:13 -0800344 public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700345 // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
Nathan Harolda2523312018-01-05 19:25:13 -0800346 Preconditions.checkNotNull(algo);
347 mConfig.setAuthentication(algo);
Nathan Harold330e1082017-01-12 18:38:57 -0800348 return this;
349 }
350
351 /**
Nathan Harolda2523312018-01-05 19:25:13 -0800352 * Set the authenticated encryption algorithm.
Benedict Wong0febe5e2017-08-22 21:42:33 -0700353 *
Nathan Harolda2523312018-01-05 19:25:13 -0800354 * <p>The Authenticated Encryption (AE) class of algorithms are also known as
355 * Authenticated Encryption with Associated Data (AEAD) algorithms, or Combined mode
356 * algorithms (as referred to in
357 * <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>).
Benedict Wong0febe5e2017-08-22 21:42:33 -0700358 *
359 * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
360 *
Benedict Wong0febe5e2017-08-22 21:42:33 -0700361 * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
362 * be applied.
363 */
Nathan Harolda2523312018-01-05 19:25:13 -0800364 public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
365 Preconditions.checkNotNull(algo);
366 mConfig.setAuthenticatedEncryption(algo);
Nathan Harold330e1082017-01-12 18:38:57 -0800367 return this;
368 }
369
370 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700371 * Add UDP encapsulation to an IPv4 transform.
Nathan Harold330e1082017-01-12 18:38:57 -0800372 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700373 * <p>This allows IPsec traffic to pass through a NAT.
Nathan Harold330e1082017-01-12 18:38:57 -0800374 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700375 * @see <a href="https://tools.ietf.org/html/rfc3948">RFC 3948, UDP Encapsulation of IPsec
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800376 * ESP Packets</a>
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700377 * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.23">RFC 7296 section 2.23,
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800378 * NAT Traversal of IKEv2</a>
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700379 * @param localSocket a socket for sending and receiving encapsulated traffic
380 * @param remotePort the UDP port number of the remote host that will send and receive
381 * encapsulated traffic. In the case of IKEv2, this should be port 4500.
Nathan Harold330e1082017-01-12 18:38:57 -0800382 */
383 public IpSecTransform.Builder setIpv4Encapsulation(
Nathan Harolda2523312018-01-05 19:25:13 -0800384 @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
385 Preconditions.checkNotNull(localSocket);
Nathan Harolda10003d2017-08-23 13:46:33 -0700386 mConfig.setEncapType(ENCAP_ESPINUDP);
Nathan Harold6119d8d2017-12-13 18:51:35 -0800387 if (localSocket.getResourceId() == INVALID_RESOURCE_ID) {
388 throw new IllegalArgumentException("Invalid UdpEncapsulationSocket");
389 }
Nathan Harolda10003d2017-08-23 13:46:33 -0700390 mConfig.setEncapSocketResourceId(localSocket.getResourceId());
391 mConfig.setEncapRemotePort(remotePort);
Nathan Harold330e1082017-01-12 18:38:57 -0800392 return this;
393 }
394
Nathan Harold330e1082017-01-12 18:38:57 -0800395 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700396 * Build a transport mode {@link IpSecTransform}.
Nathan Harold330e1082017-01-12 18:38:57 -0800397 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700398 * <p>This builds and activates a transport mode transform. Note that an active transform
399 * will not affect any network traffic until it has been applied to one or more sockets.
Nathan Harold330e1082017-01-12 18:38:57 -0800400 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700401 * @see IpSecManager#applyTransportModeTransform
Nathan Harolda2523312018-01-05 19:25:13 -0800402 * @param sourceAddress the source {@code InetAddress} of traffic on sockets that will use
403 * this transform; this address must belong to the Network used by all sockets that
404 * utilize this transform; if provided, then only traffic originating from the
405 * specified source address will be processed.
406 * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
407 * traffic
Nathan Harold330e1082017-01-12 18:38:57 -0800408 * @throws IllegalArgumentException indicating that a particular combination of transform
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700409 * properties is invalid
Nathan Harolda2523312018-01-05 19:25:13 -0800410 * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms
411 * are active
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700412 * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
413 * collides with an existing transform
414 * @throws IOException indicating other errors
Nathan Harold330e1082017-01-12 18:38:57 -0800415 */
Nathan Harolda2523312018-01-05 19:25:13 -0800416 public IpSecTransform buildTransportModeTransform(
417 @NonNull InetAddress sourceAddress,
418 @NonNull IpSecManager.SecurityParameterIndex spi)
Nathan Harold330e1082017-01-12 18:38:57 -0800419 throws IpSecManager.ResourceUnavailableException,
420 IpSecManager.SpiUnavailableException, IOException {
Nathan Harolda2523312018-01-05 19:25:13 -0800421 Preconditions.checkNotNull(sourceAddress);
422 Preconditions.checkNotNull(spi);
423 if (spi.getResourceId() == INVALID_RESOURCE_ID) {
424 throw new IllegalArgumentException("Invalid SecurityParameterIndex");
Nathan Harold6119d8d2017-12-13 18:51:35 -0800425 }
Nathan Harolda10003d2017-08-23 13:46:33 -0700426 mConfig.setMode(MODE_TRANSPORT);
Nathan Harolda2523312018-01-05 19:25:13 -0800427 mConfig.setSourceAddress(sourceAddress.getHostAddress());
428 mConfig.setSpiResourceId(spi.getResourceId());
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700429 // FIXME: modifying a builder after calling build can change the built transform.
Nathan Harold330e1082017-01-12 18:38:57 -0800430 return new IpSecTransform(mContext, mConfig).activate();
431 }
432
433 /**
434 * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some
435 * parameters have interdependencies that are checked at build time.
436 *
Nathan Harolda2523312018-01-05 19:25:13 -0800437 * @param sourceAddress the {@link InetAddress} that provides the source address for this
Nathan Harold330e1082017-01-12 18:38:57 -0800438 * IPsec tunnel. This is almost certainly an address belonging to the {@link Network}
439 * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}.
Nathan Harolda2523312018-01-05 19:25:13 -0800440 * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
441 * traffic
Nathan Harold330e1082017-01-12 18:38:57 -0800442 * @throws IllegalArgumentException indicating that a particular combination of transform
443 * properties is invalid.
Nathan Harolda2523312018-01-05 19:25:13 -0800444 * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms
445 * are active
446 * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
447 * collides with an existing transform
448 * @throws IOException indicating other errors
Nathan Harold330e1082017-01-12 18:38:57 -0800449 * @hide
450 */
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800451 @SystemApi
Nathan Harold330e1082017-01-12 18:38:57 -0800452 public IpSecTransform buildTunnelModeTransform(
Nathan Harolda2523312018-01-05 19:25:13 -0800453 @NonNull InetAddress sourceAddress,
454 @NonNull IpSecManager.SecurityParameterIndex spi)
455 throws IpSecManager.ResourceUnavailableException,
456 IpSecManager.SpiUnavailableException, IOException {
457 Preconditions.checkNotNull(sourceAddress);
458 Preconditions.checkNotNull(spi);
459 if (spi.getResourceId() == INVALID_RESOURCE_ID) {
460 throw new IllegalArgumentException("Invalid SecurityParameterIndex");
Nathan Harold6119d8d2017-12-13 18:51:35 -0800461 }
Nathan Harolda10003d2017-08-23 13:46:33 -0700462 mConfig.setMode(MODE_TUNNEL);
Nathan Harolda2523312018-01-05 19:25:13 -0800463 mConfig.setSourceAddress(sourceAddress.getHostAddress());
464 mConfig.setSpiResourceId(spi.getResourceId());
Nathan Harold330e1082017-01-12 18:38:57 -0800465 return new IpSecTransform(mContext, mConfig);
466 }
467
468 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700469 * Create a new IpSecTransform.Builder.
Nathan Harold330e1082017-01-12 18:38:57 -0800470 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700471 * @param context current context
Nathan Harold330e1082017-01-12 18:38:57 -0800472 */
Nathan Harold93962f32017-03-07 13:23:36 -0800473 public Builder(@NonNull Context context) {
474 Preconditions.checkNotNull(context);
Nathan Harold330e1082017-01-12 18:38:57 -0800475 mContext = context;
476 mConfig = new IpSecConfig();
477 }
Nathan Harold330e1082017-01-12 18:38:57 -0800478 }
479}