• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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  */
16 
17 package com.android.server;
18 
19 import static android.content.pm.PackageManager.PERMISSION_DENIED;
20 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
21 import static android.net.INetd.IF_STATE_DOWN;
22 import static android.net.INetd.IF_STATE_UP;
23 import static android.net.IpSecManager.DIRECTION_FWD;
24 import static android.net.IpSecManager.DIRECTION_IN;
25 import static android.net.IpSecManager.DIRECTION_OUT;
26 import static android.net.IpSecManager.FEATURE_IPSEC_TUNNEL_MIGRATION;
27 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
28 import static android.system.OsConstants.AF_INET;
29 import static android.system.OsConstants.AF_INET6;
30 
31 import static org.junit.Assert.assertEquals;
32 import static org.junit.Assert.assertNotNull;
33 import static org.junit.Assert.fail;
34 import static org.mockito.ArgumentMatchers.any;
35 import static org.mockito.ArgumentMatchers.anyInt;
36 import static org.mockito.ArgumentMatchers.anyLong;
37 import static org.mockito.ArgumentMatchers.anyString;
38 import static org.mockito.ArgumentMatchers.argThat;
39 import static org.mockito.ArgumentMatchers.eq;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.never;
42 import static org.mockito.Mockito.times;
43 import static org.mockito.Mockito.verify;
44 import static org.mockito.Mockito.when;
45 
46 import android.app.AppOpsManager;
47 import android.content.Context;
48 import android.content.pm.PackageManager;
49 import android.net.ConnectivityManager;
50 import android.net.INetd;
51 import android.net.InetAddresses;
52 import android.net.InterfaceConfigurationParcel;
53 import android.net.IpSecAlgorithm;
54 import android.net.IpSecConfig;
55 import android.net.IpSecManager;
56 import android.net.IpSecMigrateInfoParcel;
57 import android.net.IpSecSpiResponse;
58 import android.net.IpSecTransform;
59 import android.net.IpSecTransformResponse;
60 import android.net.IpSecTunnelInterfaceResponse;
61 import android.net.IpSecUdpEncapResponse;
62 import android.net.LinkAddress;
63 import android.net.LinkProperties;
64 import android.net.Network;
65 import android.os.Binder;
66 import android.os.Build;
67 import android.os.ParcelFileDescriptor;
68 import android.os.RemoteException;
69 import android.system.Os;
70 import android.test.mock.MockContext;
71 import android.util.ArraySet;
72 
73 import androidx.test.filters.SmallTest;
74 
75 import com.android.net.module.util.netlink.xfrm.XfrmNetlinkNewSaMessage;
76 import com.android.server.IpSecService.TunnelInterfaceRecord;
77 import com.android.testutils.DevSdkIgnoreRule;
78 
79 import org.junit.Before;
80 import org.junit.Ignore;
81 import org.junit.Rule;
82 import org.junit.Test;
83 import org.junit.runner.RunWith;
84 import org.junit.runners.Parameterized;
85 
86 import java.net.Inet4Address;
87 import java.net.InetAddress;
88 import java.net.Socket;
89 import java.util.Arrays;
90 import java.util.Collection;
91 import java.util.Set;
92 
93 /** Unit tests for {@link IpSecService}. */
94 @SmallTest
95 @RunWith(Parameterized.class)
96 public class IpSecServiceParameterizedTest {
97     @Rule
98     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(
99             Build.VERSION_CODES.S_V2 /* ignoreClassUpTo */);
100 
101     private static final int TEST_SPI = 0xD1201D;
102 
103     private final String mSourceAddr;
104     private final String mDestinationAddr;
105     private final LinkAddress mLocalInnerAddress;
106     private final int mFamily;
107 
108     private static final int[] ADDRESS_FAMILIES =
109             new int[] {AF_INET, AF_INET6};
110 
111     @Parameterized.Parameters
ipSecConfigs()112     public static Collection ipSecConfigs() {
113         return Arrays.asList(
114                 new Object[][] {
115                 {"1.2.3.4", "8.8.4.4", "10.0.1.1/24", AF_INET},
116                 {"2601::2", "2601::10", "2001:db8::1/64", AF_INET6}
117         });
118     }
119 
120     private static final byte[] AEAD_KEY = {
121         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
122         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
123         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
124         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
125         0x73, 0x61, 0x6C, 0x74
126     };
127     private static final byte[] CRYPT_KEY = {
128         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
129         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
130         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
131         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
132     };
133     private static final byte[] AUTH_KEY = {
134         0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
136         0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
138     };
139 
140     private static final String NEW_SRC_ADDRESS = "2001:db8:2::1";
141     private static final String NEW_DST_ADDRESS = "2001:db8:2::2";
142 
143     AppOpsManager mMockAppOps = mock(AppOpsManager.class);
144     ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class);
145 
146     TestContext mTestContext = new TestContext();
147 
148     private class TestContext extends MockContext {
149         private Set<String> mAllowedPermissions = new ArraySet<>(Arrays.asList(
150                 android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
151                 android.Manifest.permission.NETWORK_STACK,
152                 android.Manifest.permission.ACCESS_NETWORK_STATE,
153                 PERMISSION_MAINLINE_NETWORK_STACK));
154 
setAllowedPermissions(String... permissions)155         private void setAllowedPermissions(String... permissions) {
156             mAllowedPermissions = new ArraySet<>(permissions);
157         }
158 
159         @Override
getSystemService(String name)160         public Object getSystemService(String name) {
161             switch(name) {
162                 case Context.APP_OPS_SERVICE:
163                     return mMockAppOps;
164                 case Context.CONNECTIVITY_SERVICE:
165                     return mMockConnectivityMgr;
166                 default:
167                     return null;
168             }
169         }
170 
171         @Override
getSystemServiceName(Class<?> serviceClass)172         public String getSystemServiceName(Class<?> serviceClass) {
173             if (ConnectivityManager.class == serviceClass) {
174                 return Context.CONNECTIVITY_SERVICE;
175             }
176             return null;
177         }
178 
179         @Override
getPackageManager()180         public PackageManager getPackageManager() {
181             return mMockPkgMgr;
182         }
183 
184         @Override
enforceCallingOrSelfPermission(String permission, String message)185         public void enforceCallingOrSelfPermission(String permission, String message) {
186             if (mAllowedPermissions.contains(permission)) {
187                 return;
188             } else {
189                 throw new SecurityException("Unavailable permission requested");
190             }
191         }
192 
193         @Override
checkCallingOrSelfPermission(String permission)194         public int checkCallingOrSelfPermission(String permission) {
195             if (mAllowedPermissions.contains(permission)) {
196                 return PERMISSION_GRANTED;
197             } else {
198                 return PERMISSION_DENIED;
199             }
200         }
201     }
202 
makeDependencies()203     private IpSecService.Dependencies makeDependencies() throws RemoteException {
204         final IpSecService.Dependencies deps = mock(IpSecService.Dependencies.class);
205         when(deps.getNetdInstance(mTestContext)).thenReturn(mMockNetd);
206         when(deps.getIpSecXfrmController()).thenReturn(mMockXfrmCtrl);
207         return deps;
208     }
209 
210     INetd mMockNetd;
211     PackageManager mMockPkgMgr;
212     IpSecXfrmController mMockXfrmCtrl;
213     IpSecService.Dependencies mDeps;
214     IpSecService mIpSecService;
215     Network fakeNetwork = new Network(0xAB);
216     int mUid = Os.getuid();
217 
218     private static final IpSecAlgorithm AUTH_ALGO =
219             new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
220     private static final IpSecAlgorithm CRYPT_ALGO =
221             new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
222     private static final IpSecAlgorithm AEAD_ALGO =
223             new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
224     private static final int REMOTE_ENCAP_PORT = 4500;
225 
226     private static final String BLESSED_PACKAGE = "blessedPackage";
227     private static final String SYSTEM_PACKAGE = "systemPackage";
228     private static final String BAD_PACKAGE = "badPackage";
229 
IpSecServiceParameterizedTest( String sourceAddr, String destAddr, String localInnerAddr, int family)230     public IpSecServiceParameterizedTest(
231             String sourceAddr, String destAddr, String localInnerAddr, int family) {
232         mSourceAddr = sourceAddr;
233         mDestinationAddr = destAddr;
234         mLocalInnerAddress = new LinkAddress(localInnerAddr);
235         mFamily = family;
236     }
237 
238     @Before
setUp()239     public void setUp() throws Exception {
240         mMockNetd = mock(INetd.class);
241         mMockXfrmCtrl = mock(IpSecXfrmController.class);
242         mMockPkgMgr = mock(PackageManager.class);
243         mDeps = makeDependencies();
244         mIpSecService = new IpSecService(mTestContext, mDeps);
245 
246         // PackageManager should always return true (feature flag tests in IpSecServiceTest)
247         when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
248 
249         // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
250         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BLESSED_PACKAGE)))
251                 .thenReturn(AppOpsManager.MODE_ALLOWED);
252         // A system package will not be granted the app op, so this should fall back to
253         // a permissions check, which should pass.
254         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(SYSTEM_PACKAGE)))
255                 .thenReturn(AppOpsManager.MODE_DEFAULT);
256         // A mismatch between the package name and the UID will return MODE_IGNORED.
257         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BAD_PACKAGE)))
258                 .thenReturn(AppOpsManager.MODE_IGNORED);
259     }
260 
261     //TODO: Add a test to verify SPI.
262 
263     @Test
testIpSecServiceReserveSpi()264     public void testIpSecServiceReserveSpi() throws Exception {
265         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
266                 .thenReturn(TEST_SPI);
267 
268         IpSecSpiResponse spiResp =
269                 mIpSecService.allocateSecurityParameterIndex(
270                         mDestinationAddr, TEST_SPI, new Binder());
271         assertEquals(IpSecManager.Status.OK, spiResp.status);
272         assertEquals(TEST_SPI, spiResp.spi);
273     }
274 
275     @Test
testReleaseSecurityParameterIndex()276     public void testReleaseSecurityParameterIndex() throws Exception {
277         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
278                 .thenReturn(TEST_SPI);
279 
280         IpSecSpiResponse spiResp =
281                 mIpSecService.allocateSecurityParameterIndex(
282                         mDestinationAddr, TEST_SPI, new Binder());
283 
284         mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
285 
286         verify(mMockNetd)
287                 .ipSecDeleteSecurityAssociation(
288                         eq(mUid),
289                         anyString(),
290                         anyString(),
291                         eq(TEST_SPI),
292                         anyInt(),
293                         anyInt(),
294                         anyInt());
295 
296         // Verify quota and RefcountedResource objects cleaned up
297         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
298         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
299         try {
300             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
301             fail("Expected IllegalArgumentException on attempt to access deleted resource");
302         } catch (IllegalArgumentException expected) {
303 
304         }
305     }
306 
307     @Test
testSecurityParameterIndexBinderDeath()308     public void testSecurityParameterIndexBinderDeath() throws Exception {
309         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
310                 .thenReturn(TEST_SPI);
311 
312         IpSecSpiResponse spiResp =
313                 mIpSecService.allocateSecurityParameterIndex(
314                         mDestinationAddr, TEST_SPI, new Binder());
315 
316         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
317         IpSecService.RefcountedResource refcountedRecord =
318                 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
319 
320         refcountedRecord.binderDied();
321 
322         verify(mMockNetd)
323                 .ipSecDeleteSecurityAssociation(
324                         eq(mUid),
325                         anyString(),
326                         anyString(),
327                         eq(TEST_SPI),
328                         anyInt(),
329                         anyInt(),
330                         anyInt());
331 
332         // Verify quota and RefcountedResource objects cleaned up
333         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
334         try {
335             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
336             fail("Expected IllegalArgumentException on attempt to access deleted resource");
337         } catch (IllegalArgumentException expected) {
338 
339         }
340     }
341 
getNewSpiResourceId(String remoteAddress, int returnSpi)342     private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
343         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
344                 .thenReturn(returnSpi);
345 
346         IpSecSpiResponse spi =
347                 mIpSecService.allocateSecurityParameterIndex(
348                         InetAddresses.parseNumericAddress(remoteAddress).getHostAddress(),
349                         IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
350                         new Binder());
351         return spi.resourceId;
352     }
353 
addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config)354     private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
355         config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
356         config.setSourceAddress(mSourceAddr);
357         config.setDestinationAddress(mDestinationAddr);
358     }
359 
addAuthAndCryptToIpSecConfig(IpSecConfig config)360     private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
361         config.setEncryption(CRYPT_ALGO);
362         config.setAuthentication(AUTH_ALGO);
363     }
364 
addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config)365     private void addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config) throws Exception {
366         config.setEncapType(IpSecTransform.ENCAP_ESPINUDP);
367         config.setEncapSocketResourceId(resourceId);
368         config.setEncapRemotePort(REMOTE_ENCAP_PORT);
369     }
370 
verifyTransformNetdCalledForCreatingSA( IpSecConfig config, IpSecTransformResponse resp)371     private void verifyTransformNetdCalledForCreatingSA(
372             IpSecConfig config, IpSecTransformResponse resp) throws Exception {
373         verifyTransformNetdCalledForCreatingSA(config, resp, 0);
374     }
375 
verifyTransformNetdCalledForCreatingSA( IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort)376     private void verifyTransformNetdCalledForCreatingSA(
377             IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort) throws Exception {
378         IpSecAlgorithm auth = config.getAuthentication();
379         IpSecAlgorithm crypt = config.getEncryption();
380         IpSecAlgorithm authCrypt = config.getAuthenticatedEncryption();
381 
382         verify(mMockNetd, times(1))
383                 .ipSecAddSecurityAssociation(
384                         eq(mUid),
385                         eq(config.getMode()),
386                         eq(mSourceAddr),
387                         eq(mDestinationAddr),
388                         eq((config.getNetwork() != null) ? config.getNetwork().netId : 0),
389                         eq(TEST_SPI),
390                         eq(0),
391                         eq(0),
392                         eq((auth != null) ? auth.getName() : ""),
393                         eq((auth != null) ? auth.getKey() : new byte[] {}),
394                         eq((auth != null) ? auth.getTruncationLengthBits() : 0),
395                         eq((crypt != null) ? crypt.getName() : ""),
396                         eq((crypt != null) ? crypt.getKey() : new byte[] {}),
397                         eq((crypt != null) ? crypt.getTruncationLengthBits() : 0),
398                         eq((authCrypt != null) ? authCrypt.getName() : ""),
399                         eq((authCrypt != null) ? authCrypt.getKey() : new byte[] {}),
400                         eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
401                         eq(config.getEncapType()),
402                         eq(encapSocketPort),
403                         eq(config.getEncapRemotePort()),
404                         eq(config.getXfrmInterfaceId()));
405     }
406 
407     @Test
testCreateTransform()408     public void testCreateTransform() throws Exception {
409         IpSecConfig ipSecConfig = new IpSecConfig();
410         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
411         addAuthAndCryptToIpSecConfig(ipSecConfig);
412 
413         IpSecTransformResponse createTransformResp =
414                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
415         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
416 
417         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
418     }
419 
420     @Test
testCreateTransformAead()421     public void testCreateTransformAead() throws Exception {
422         IpSecConfig ipSecConfig = new IpSecConfig();
423         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
424 
425         ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
426 
427         IpSecTransformResponse createTransformResp =
428                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
429         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
430 
431         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
432     }
433 
434     @Test
testCreateTransportModeTransformWithEncap()435     public void testCreateTransportModeTransformWithEncap() throws Exception {
436         IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
437 
438         IpSecConfig ipSecConfig = new IpSecConfig();
439         ipSecConfig.setMode(IpSecTransform.MODE_TRANSPORT);
440         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
441         addAuthAndCryptToIpSecConfig(ipSecConfig);
442         addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
443 
444         if (mFamily == AF_INET) {
445             IpSecTransformResponse createTransformResp =
446                     mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
447             assertEquals(IpSecManager.Status.OK, createTransformResp.status);
448 
449             verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
450         } else {
451             try {
452                 IpSecTransformResponse createTransformResp =
453                         mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
454                 fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
455             } catch (IllegalArgumentException expected) {
456             }
457         }
458     }
459 
460     @Test
testCreateTunnelModeTransformWithEncap()461     public void testCreateTunnelModeTransformWithEncap() throws Exception {
462         IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
463 
464         IpSecConfig ipSecConfig = new IpSecConfig();
465         ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
466         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
467         addAuthAndCryptToIpSecConfig(ipSecConfig);
468         addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
469 
470         if (mFamily == AF_INET) {
471             IpSecTransformResponse createTransformResp =
472                     mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
473             assertEquals(IpSecManager.Status.OK, createTransformResp.status);
474 
475             verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
476         } else {
477             try {
478                 IpSecTransformResponse createTransformResp =
479                         mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
480                 fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
481             } catch (IllegalArgumentException expected) {
482             }
483         }
484     }
485 
486     @Test
testCreateTwoTransformsWithSameSpis()487     public void testCreateTwoTransformsWithSameSpis() throws Exception {
488         IpSecConfig ipSecConfig = new IpSecConfig();
489         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
490         addAuthAndCryptToIpSecConfig(ipSecConfig);
491 
492         IpSecTransformResponse createTransformResp =
493                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
494         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
495 
496         // Attempting to create transform a second time with the same SPIs should throw an error...
497         try {
498             mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
499                 fail("IpSecService should have thrown an error for reuse of SPI");
500         } catch (IllegalStateException expected) {
501         }
502 
503         // ... even if the transform is deleted
504         mIpSecService.deleteTransform(createTransformResp.resourceId);
505         try {
506             mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
507                 fail("IpSecService should have thrown an error for reuse of SPI");
508         } catch (IllegalStateException expected) {
509         }
510     }
511 
512     @Test
getTransformState()513     public void getTransformState() throws Exception {
514         XfrmNetlinkNewSaMessage mockXfrmNewSaMsg = mock(XfrmNetlinkNewSaMessage.class);
515         when(mockXfrmNewSaMsg.getBitmap()).thenReturn(new byte[512]);
516         when(mMockXfrmCtrl.ipSecGetSa(any(InetAddress.class), anyLong()))
517                 .thenReturn(mockXfrmNewSaMsg);
518 
519         // Create transform
520         IpSecConfig ipSecConfig = new IpSecConfig();
521         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
522         addAuthAndCryptToIpSecConfig(ipSecConfig);
523 
524         IpSecTransformResponse createTransformResp =
525                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
526         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
527 
528         // Get transform state
529         mIpSecService.getTransformState(createTransformResp.resourceId);
530 
531         // Verifications
532         verify(mMockXfrmCtrl)
533                 .ipSecGetSa(
534                         eq(InetAddresses.parseNumericAddress(mDestinationAddr)),
535                         eq(Integer.toUnsignedLong(TEST_SPI)));
536     }
537 
538     @Test
testReleaseOwnedSpi()539     public void testReleaseOwnedSpi() throws Exception {
540         IpSecConfig ipSecConfig = new IpSecConfig();
541         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
542         addAuthAndCryptToIpSecConfig(ipSecConfig);
543 
544         IpSecTransformResponse createTransformResp =
545                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
546         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
547         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
548         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
549         verify(mMockNetd, times(0))
550                 .ipSecDeleteSecurityAssociation(
551                         eq(mUid),
552                         anyString(),
553                         anyString(),
554                         eq(TEST_SPI),
555                         anyInt(),
556                         anyInt(),
557                         anyInt());
558         // quota is not released until the SPI is released by the Transform
559         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
560     }
561 
562     @Test
testDeleteTransform()563     public void testDeleteTransform() throws Exception {
564         IpSecConfig ipSecConfig = new IpSecConfig();
565         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
566         addAuthAndCryptToIpSecConfig(ipSecConfig);
567 
568         IpSecTransformResponse createTransformResp =
569                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
570         mIpSecService.deleteTransform(createTransformResp.resourceId);
571 
572         verify(mMockNetd, times(1))
573                 .ipSecDeleteSecurityAssociation(
574                         eq(mUid),
575                         anyString(),
576                         anyString(),
577                         eq(TEST_SPI),
578                         anyInt(),
579                         anyInt(),
580                         anyInt());
581 
582         // Verify quota and RefcountedResource objects cleaned up
583         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
584         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
585         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
586 
587         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
588         // Verify that ipSecDeleteSa was not called when the SPI was released because the
589         // ownedByTransform property should prevent it; (note, the called count is cumulative).
590         verify(mMockNetd, times(1))
591                 .ipSecDeleteSecurityAssociation(
592                         anyInt(),
593                         anyString(),
594                         anyString(),
595                         anyInt(),
596                         anyInt(),
597                         anyInt(),
598                         anyInt());
599         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
600 
601         try {
602             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
603                     createTransformResp.resourceId);
604             fail("Expected IllegalArgumentException on attempt to access deleted resource");
605         } catch (IllegalArgumentException expected) {
606 
607         }
608     }
609 
610     @Test
testTransportModeTransformBinderDeath()611     public void testTransportModeTransformBinderDeath() throws Exception {
612         IpSecConfig ipSecConfig = new IpSecConfig();
613         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
614         addAuthAndCryptToIpSecConfig(ipSecConfig);
615 
616         IpSecTransformResponse createTransformResp =
617                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
618 
619         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
620         IpSecService.RefcountedResource refcountedRecord =
621                 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
622                         createTransformResp.resourceId);
623 
624         refcountedRecord.binderDied();
625 
626         verify(mMockNetd)
627                 .ipSecDeleteSecurityAssociation(
628                         eq(mUid),
629                         anyString(),
630                         anyString(),
631                         eq(TEST_SPI),
632                         anyInt(),
633                         anyInt(),
634                         anyInt());
635 
636         // Verify quota and RefcountedResource objects cleaned up
637         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
638         try {
639             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
640                     createTransformResp.resourceId);
641             fail("Expected IllegalArgumentException on attempt to access deleted resource");
642         } catch (IllegalArgumentException expected) {
643 
644         }
645     }
646 
647     @Test
testApplyTransportModeTransform()648     public void testApplyTransportModeTransform() throws Exception {
649         verifyApplyTransportModeTransformCommon(false);
650     }
651 
652     @Test
testApplyTransportModeTransformReleasedSpi()653     public void testApplyTransportModeTransformReleasedSpi() throws Exception {
654         verifyApplyTransportModeTransformCommon(true);
655     }
656 
verifyApplyTransportModeTransformCommon( boolean closeSpiBeforeApply)657     public void verifyApplyTransportModeTransformCommon(
658                 boolean closeSpiBeforeApply) throws Exception {
659         IpSecConfig ipSecConfig = new IpSecConfig();
660         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
661         addAuthAndCryptToIpSecConfig(ipSecConfig);
662 
663         IpSecTransformResponse createTransformResp =
664                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
665 
666         if (closeSpiBeforeApply) {
667             mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
668         }
669 
670         Socket socket = new Socket();
671         socket.bind(null);
672         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
673 
674         int resourceId = createTransformResp.resourceId;
675         mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
676 
677         verify(mMockNetd)
678                 .ipSecApplyTransportModeTransform(
679                         eq(pfd),
680                         eq(mUid),
681                         eq(IpSecManager.DIRECTION_OUT),
682                         anyString(),
683                         anyString(),
684                         eq(TEST_SPI));
685     }
686 
687     @Test
testApplyTransportModeTransformWithClosedSpi()688     public void testApplyTransportModeTransformWithClosedSpi() throws Exception {
689         IpSecConfig ipSecConfig = new IpSecConfig();
690         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
691         addAuthAndCryptToIpSecConfig(ipSecConfig);
692 
693         IpSecTransformResponse createTransformResp =
694                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
695 
696         // Close SPI record
697         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
698 
699         Socket socket = new Socket();
700         socket.bind(null);
701         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
702 
703         int resourceId = createTransformResp.resourceId;
704         mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
705 
706         verify(mMockNetd)
707                 .ipSecApplyTransportModeTransform(
708                         eq(pfd),
709                         eq(mUid),
710                         eq(IpSecManager.DIRECTION_OUT),
711                         anyString(),
712                         anyString(),
713                         eq(TEST_SPI));
714     }
715 
716     @Test
testRemoveTransportModeTransform()717     public void testRemoveTransportModeTransform() throws Exception {
718         Socket socket = new Socket();
719         socket.bind(null);
720         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
721         mIpSecService.removeTransportModeTransforms(pfd);
722 
723         verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
724     }
725 
createAndValidateTunnel( String localAddr, String remoteAddr, String pkgName)726     private IpSecTunnelInterfaceResponse createAndValidateTunnel(
727             String localAddr, String remoteAddr, String pkgName) throws Exception {
728         final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
729         config.flags = new String[] {IF_STATE_DOWN};
730         when(mMockNetd.interfaceGetCfg(anyString())).thenReturn(config);
731         IpSecTunnelInterfaceResponse createTunnelResp =
732                 mIpSecService.createTunnelInterface(
733                         mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
734 
735         assertNotNull(createTunnelResp);
736         assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
737         for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT, DIRECTION_FWD}) {
738             for (int selAddrFamily : ADDRESS_FAMILIES) {
739                 verify(mMockNetd).ipSecAddSecurityPolicy(
740                         eq(mUid),
741                         eq(selAddrFamily),
742                         eq(direction),
743                         anyString(),
744                         anyString(),
745                         eq(0),
746                         anyInt(), // iKey/oKey
747                         anyInt(), // mask
748                         eq(createTunnelResp.resourceId));
749             }
750         }
751 
752         return createTunnelResp;
753     }
754 
755     @Test
testCreateTunnelInterface()756     public void testCreateTunnelInterface() throws Exception {
757         IpSecTunnelInterfaceResponse createTunnelResp =
758                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
759 
760         // Check that we have stored the tracking object, and retrieve it
761         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
762         IpSecService.RefcountedResource refcountedRecord =
763                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
764                         createTunnelResp.resourceId);
765 
766         assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
767         verify(mMockNetd)
768                 .ipSecAddTunnelInterface(
769                         eq(createTunnelResp.interfaceName),
770                         eq(mSourceAddr),
771                         eq(mDestinationAddr),
772                         anyInt(),
773                         anyInt(),
774                         anyInt());
775         verify(mMockNetd).interfaceSetCfg(argThat(
776                 config -> Arrays.asList(config.flags).contains(IF_STATE_UP)));
777     }
778 
779     @Test
testDeleteTunnelInterface()780     public void testDeleteTunnelInterface() throws Exception {
781         IpSecTunnelInterfaceResponse createTunnelResp =
782                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
783 
784         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
785 
786         mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, BLESSED_PACKAGE);
787 
788         // Verify quota and RefcountedResource objects cleaned up
789         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
790         verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
791 
792         for (int direction : new int[] {DIRECTION_OUT, DIRECTION_IN, DIRECTION_FWD}) {
793             verify(mMockNetd, times(ADDRESS_FAMILIES.length))
794                     .ipSecDeleteSecurityPolicy(
795                             anyInt(), anyInt(), eq(direction), anyInt(), anyInt(), anyInt());
796         }
797 
798         try {
799             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
800                     createTunnelResp.resourceId);
801             fail("Expected IllegalArgumentException on attempt to access deleted resource");
802         } catch (IllegalArgumentException expected) {
803         }
804     }
805 
createFakeUnderlyingNetwork(String interfaceName)806     private Network createFakeUnderlyingNetwork(String interfaceName) {
807         final Network fakeNetwork = new Network(1000);
808         final LinkProperties fakeLp = new LinkProperties();
809         fakeLp.setInterfaceName(interfaceName);
810         when(mMockConnectivityMgr.getLinkProperties(eq(fakeNetwork))).thenReturn(fakeLp);
811         return fakeNetwork;
812     }
813 
814     @Test
testSetNetworkForTunnelInterface()815     public void testSetNetworkForTunnelInterface() throws Exception {
816         final IpSecTunnelInterfaceResponse createTunnelResp =
817                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
818         final Network newFakeNetwork = createFakeUnderlyingNetwork("newFakeNetworkInterface");
819         final int tunnelIfaceResourceId = createTunnelResp.resourceId;
820         mIpSecService.setNetworkForTunnelInterface(
821                 tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
822 
823         final IpSecService.UserRecord userRecord =
824                 mIpSecService.mUserResourceTracker.getUserRecord(mUid);
825         assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
826 
827         final TunnelInterfaceRecord tunnelInterfaceInfo =
828                 userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
829         assertEquals(newFakeNetwork, tunnelInterfaceInfo.getUnderlyingNetwork());
830     }
831 
832     @Test
testSetNetworkForTunnelInterfaceFailsForNullLp()833     public void testSetNetworkForTunnelInterfaceFailsForNullLp() throws Exception {
834         final IpSecTunnelInterfaceResponse createTunnelResp =
835                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
836         final Network newFakeNetwork = new Network(1000);
837         final int tunnelIfaceResourceId = createTunnelResp.resourceId;
838 
839         try {
840             mIpSecService.setNetworkForTunnelInterface(
841                     tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
842             fail(
843                     "Expected an IllegalArgumentException for underlying network with null"
844                             + " LinkProperties");
845         } catch (IllegalArgumentException expected) {
846         }
847     }
848 
849     @Test
testSetNetworkForTunnelInterfaceFailsForInvalidResourceId()850     public void testSetNetworkForTunnelInterfaceFailsForInvalidResourceId() throws Exception {
851         final IpSecTunnelInterfaceResponse createTunnelResp =
852                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
853         final Network newFakeNetwork = new Network(1000);
854 
855         try {
856             mIpSecService.setNetworkForTunnelInterface(
857                     IpSecManager.INVALID_RESOURCE_ID, newFakeNetwork, BLESSED_PACKAGE);
858             fail("Expected an IllegalArgumentException for invalid resource ID.");
859         } catch (IllegalArgumentException expected) {
860         }
861     }
862 
863     @Test
testSetNetworkForTunnelInterfaceFailsWhenSettingTunnelNetwork()864     public void testSetNetworkForTunnelInterfaceFailsWhenSettingTunnelNetwork() throws Exception {
865         final IpSecTunnelInterfaceResponse createTunnelResp =
866                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
867         final int tunnelIfaceResourceId = createTunnelResp.resourceId;
868         final IpSecService.UserRecord userRecord =
869                 mIpSecService.mUserResourceTracker.getUserRecord(mUid);
870         final TunnelInterfaceRecord tunnelInterfaceInfo =
871                 userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
872 
873         final Network newFakeNetwork =
874                 createFakeUnderlyingNetwork(tunnelInterfaceInfo.getInterfaceName());
875 
876         try {
877             mIpSecService.setNetworkForTunnelInterface(
878                     tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
879             fail(
880                     "Expected an IllegalArgumentException because the underlying network is the"
881                             + " network being exposed by this tunnel.");
882         } catch (IllegalArgumentException expected) {
883         }
884     }
885 
886     @Test
testTunnelInterfaceBinderDeath()887     public void testTunnelInterfaceBinderDeath() throws Exception {
888         IpSecTunnelInterfaceResponse createTunnelResp =
889                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
890 
891         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
892         IpSecService.RefcountedResource refcountedRecord =
893                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
894                         createTunnelResp.resourceId);
895 
896         refcountedRecord.binderDied();
897 
898         // Verify quota and RefcountedResource objects cleaned up
899         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
900         verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
901         try {
902             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
903                     createTunnelResp.resourceId);
904             fail("Expected IllegalArgumentException on attempt to access deleted resource");
905         } catch (IllegalArgumentException expected) {
906         }
907     }
908 
909     @Test
testApplyTunnelModeTransformOutbound()910     public void testApplyTunnelModeTransformOutbound() throws Exception {
911         verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
912     }
913 
914     @Test
testApplyTunnelModeTransformOutboundNonNetworkStack()915     public void testApplyTunnelModeTransformOutboundNonNetworkStack() throws Exception {
916         mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
917         verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
918     }
919 
920     @Test
testApplyTunnelModeTransformOutboundReleasedSpi()921     public void testApplyTunnelModeTransformOutboundReleasedSpi() throws Exception {
922         verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_OUT);
923     }
924 
925     @Test
testApplyTunnelModeTransformInbound()926     public void testApplyTunnelModeTransformInbound() throws Exception {
927         verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
928     }
929 
930     @Test
testApplyTunnelModeTransformInboundNonNetworkStack()931     public void testApplyTunnelModeTransformInboundNonNetworkStack() throws Exception {
932         mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
933         verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
934     }
935 
936     @Test
testApplyTunnelModeTransformForward()937     public void testApplyTunnelModeTransformForward() throws Exception {
938         verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
939     }
940 
941     @Test
testApplyTunnelModeTransformForwardNonNetworkStack()942     public void testApplyTunnelModeTransformForwardNonNetworkStack() throws Exception {
943         mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
944 
945         try {
946             verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
947             fail("Expected security exception due to use of forward policies without NETWORK_STACK"
948                      + " or MAINLINE_NETWORK_STACK permission");
949         } catch (SecurityException expected) {
950         }
951     }
952 
953     @Test
954     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
testApplyAndMigrateTunnelModeTransformOutbound()955     public void testApplyAndMigrateTunnelModeTransformOutbound() throws Exception {
956         verifyApplyAndMigrateTunnelModeTransformCommon(false, DIRECTION_OUT);
957     }
958 
959     @Test
960     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
testApplyAndMigrateTunnelModeTransformOutboundReleasedSpi()961     public void testApplyAndMigrateTunnelModeTransformOutboundReleasedSpi() throws Exception {
962         verifyApplyAndMigrateTunnelModeTransformCommon(true, DIRECTION_OUT);
963     }
964 
965     @Test
966     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
testApplyAndMigrateTunnelModeTransformInbound()967     public void testApplyAndMigrateTunnelModeTransformInbound() throws Exception {
968         verifyApplyAndMigrateTunnelModeTransformCommon(false, DIRECTION_IN);
969     }
970 
971     @Test
972     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
testApplyAndMigrateTunnelModeTransformInboundReleasedSpi()973     public void testApplyAndMigrateTunnelModeTransformInboundReleasedSpi() throws Exception {
974         verifyApplyAndMigrateTunnelModeTransformCommon(true, DIRECTION_IN);
975     }
976 
977     @Test
978     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
testApplyAndMigrateTunnelModeTransformForward()979     public void testApplyAndMigrateTunnelModeTransformForward() throws Exception {
980         verifyApplyAndMigrateTunnelModeTransformCommon(false, DIRECTION_FWD);
981     }
982 
983     @Test
984     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
testApplyAndMigrateTunnelModeTransformForwardReleasedSpi()985     public void testApplyAndMigrateTunnelModeTransformForwardReleasedSpi() throws Exception {
986         verifyApplyAndMigrateTunnelModeTransformCommon(true, DIRECTION_FWD);
987     }
988 
verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply, int direction)989     public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply, int direction)
990             throws Exception {
991         verifyApplyTunnelModeTransformCommon(
992                 new IpSecConfig(), closeSpiBeforeApply, false /* isMigrating */, direction);
993     }
994 
verifyApplyAndMigrateTunnelModeTransformCommon( boolean closeSpiBeforeApply, int direction)995     public void verifyApplyAndMigrateTunnelModeTransformCommon(
996             boolean closeSpiBeforeApply, int direction) throws Exception {
997         verifyApplyTunnelModeTransformCommon(
998                 new IpSecConfig(), closeSpiBeforeApply, true /* isMigrating */, direction);
999     }
1000 
verifyApplyTunnelModeTransformCommon( IpSecConfig ipSecConfig, boolean closeSpiBeforeApply, boolean isMigrating, int direction)1001     public int verifyApplyTunnelModeTransformCommon(
1002             IpSecConfig ipSecConfig,
1003             boolean closeSpiBeforeApply,
1004             boolean isMigrating,
1005             int direction)
1006             throws Exception {
1007         ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
1008         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
1009         addAuthAndCryptToIpSecConfig(ipSecConfig);
1010 
1011         IpSecTransformResponse createTransformResp =
1012                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
1013         IpSecTunnelInterfaceResponse createTunnelResp =
1014                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
1015 
1016         if (closeSpiBeforeApply) {
1017             mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
1018         }
1019 
1020         int transformResourceId = createTransformResp.resourceId;
1021         int tunnelResourceId = createTunnelResp.resourceId;
1022 
1023         if (isMigrating) {
1024             mIpSecService.migrateTransform(
1025                     transformResourceId, NEW_SRC_ADDRESS, NEW_DST_ADDRESS, BLESSED_PACKAGE);
1026         }
1027 
1028         mIpSecService.applyTunnelModeTransform(
1029                 tunnelResourceId, direction, transformResourceId, BLESSED_PACKAGE);
1030 
1031         for (int selAddrFamily : ADDRESS_FAMILIES) {
1032             verify(mMockNetd)
1033                     .ipSecUpdateSecurityPolicy(
1034                             eq(mUid),
1035                             eq(selAddrFamily),
1036                             eq(direction),
1037                             anyString(),
1038                             anyString(),
1039                             eq(direction == DIRECTION_OUT ? TEST_SPI : 0),
1040                             anyInt(), // iKey/oKey
1041                             anyInt(), // mask
1042                             eq(tunnelResourceId));
1043         }
1044 
1045         ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
1046         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
1047 
1048         if (isMigrating) {
1049             verify(mMockNetd, times(ADDRESS_FAMILIES.length))
1050                     .ipSecMigrate(any(IpSecMigrateInfoParcel.class));
1051         } else {
1052             verify(mMockNetd, never()).ipSecMigrate(any());
1053         }
1054 
1055         return tunnelResourceId;
1056     }
1057 
1058     @Test
testApplyTunnelModeTransformWithClosedSpi()1059     public void testApplyTunnelModeTransformWithClosedSpi() throws Exception {
1060         IpSecConfig ipSecConfig = new IpSecConfig();
1061         ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
1062         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
1063         addAuthAndCryptToIpSecConfig(ipSecConfig);
1064 
1065         IpSecTransformResponse createTransformResp =
1066                 mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
1067         IpSecTunnelInterfaceResponse createTunnelResp =
1068                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
1069 
1070         // Close SPI record
1071         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
1072 
1073         int transformResourceId = createTransformResp.resourceId;
1074         int tunnelResourceId = createTunnelResp.resourceId;
1075         mIpSecService.applyTunnelModeTransform(
1076                 tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
1077 
1078         for (int selAddrFamily : ADDRESS_FAMILIES) {
1079             verify(mMockNetd)
1080                     .ipSecUpdateSecurityPolicy(
1081                             eq(mUid),
1082                             eq(selAddrFamily),
1083                             eq(IpSecManager.DIRECTION_OUT),
1084                             anyString(),
1085                             anyString(),
1086                             eq(TEST_SPI),
1087                             anyInt(), // iKey/oKey
1088                             anyInt(), // mask
1089                             eq(tunnelResourceId));
1090         }
1091 
1092         ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
1093         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
1094     }
1095 
1096     @Test
testAddRemoveAddressFromTunnelInterface()1097     public void testAddRemoveAddressFromTunnelInterface() throws Exception {
1098         for (String pkgName : new String[] {BLESSED_PACKAGE, SYSTEM_PACKAGE}) {
1099             IpSecTunnelInterfaceResponse createTunnelResp =
1100                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
1101             mIpSecService.addAddressToTunnelInterface(
1102                     createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
1103             verify(mMockNetd, times(1))
1104                     .interfaceAddAddress(
1105                             eq(createTunnelResp.interfaceName),
1106                             eq(mLocalInnerAddress.getAddress().getHostAddress()),
1107                             eq(mLocalInnerAddress.getPrefixLength()));
1108             mIpSecService.removeAddressFromTunnelInterface(
1109                     createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
1110             verify(mMockNetd, times(1))
1111                     .interfaceDelAddress(
1112                             eq(createTunnelResp.interfaceName),
1113                             eq(mLocalInnerAddress.getAddress().getHostAddress()),
1114                             eq(mLocalInnerAddress.getPrefixLength()));
1115             mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
1116         }
1117     }
1118 
1119     @Ignore
1120     @Test
testAddTunnelFailsForBadPackageName()1121     public void testAddTunnelFailsForBadPackageName() throws Exception {
1122         try {
1123             IpSecTunnelInterfaceResponse createTunnelResp =
1124                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, BAD_PACKAGE);
1125             fail("Expected a SecurityException for badPackage.");
1126         } catch (SecurityException expected) {
1127         }
1128     }
1129 
1130     @Test
testFeatureFlagIpSecTunnelsVerification()1131     public void testFeatureFlagIpSecTunnelsVerification() throws Exception {
1132         when(mMockPkgMgr.hasSystemFeature(eq(PackageManager.FEATURE_IPSEC_TUNNELS)))
1133                 .thenReturn(false);
1134 
1135         try {
1136             String addr = Inet4Address.getLoopbackAddress().getHostAddress();
1137             mIpSecService.createTunnelInterface(
1138                     addr, addr, new Network(0), new Binder(), BLESSED_PACKAGE);
1139             fail("Expected UnsupportedOperationException for disabled feature");
1140         } catch (UnsupportedOperationException expected) {
1141         }
1142     }
1143 
1144     @Test
1145     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
testFeatureFlagIpSecTunnelMigrationVerification()1146     public void testFeatureFlagIpSecTunnelMigrationVerification() throws Exception {
1147         when(mMockPkgMgr.hasSystemFeature(eq(FEATURE_IPSEC_TUNNEL_MIGRATION))).thenReturn(false);
1148 
1149         try {
1150             mIpSecService.migrateTransform(
1151                     1 /* transformId */, NEW_SRC_ADDRESS, NEW_DST_ADDRESS, BLESSED_PACKAGE);
1152             fail("Expected UnsupportedOperationException for disabled feature");
1153         } catch (UnsupportedOperationException expected) {
1154         }
1155     }
1156 }
1157