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