• 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.system.OsConstants.AF_INET;
20 import static android.system.OsConstants.AF_INET6;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.fail;
25 import static org.mockito.Matchers.anyInt;
26 import static org.mockito.Matchers.anyString;
27 import static org.mockito.Matchers.eq;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.app.AppOpsManager;
34 import android.content.Context;
35 import android.content.pm.PackageManager;
36 import android.net.INetd;
37 import android.net.IpSecAlgorithm;
38 import android.net.IpSecConfig;
39 import android.net.IpSecManager;
40 import android.net.IpSecSpiResponse;
41 import android.net.IpSecTransform;
42 import android.net.IpSecTransformResponse;
43 import android.net.IpSecTunnelInterfaceResponse;
44 import android.net.IpSecUdpEncapResponse;
45 import android.net.LinkAddress;
46 import android.net.Network;
47 import android.net.NetworkUtils;
48 import android.os.Binder;
49 import android.os.ParcelFileDescriptor;
50 import android.system.Os;
51 import android.test.mock.MockContext;
52 
53 import androidx.test.filters.SmallTest;
54 
55 import org.junit.Before;
56 import org.junit.Ignore;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 import org.junit.runners.Parameterized;
60 
61 import java.net.Inet4Address;
62 import java.net.Socket;
63 import java.util.Arrays;
64 import java.util.Collection;
65 
66 /** Unit tests for {@link IpSecService}. */
67 @SmallTest
68 @RunWith(Parameterized.class)
69 public class IpSecServiceParameterizedTest {
70 
71     private static final int TEST_SPI = 0xD1201D;
72 
73     private final String mSourceAddr;
74     private final String mDestinationAddr;
75     private final LinkAddress mLocalInnerAddress;
76     private final int mFamily;
77 
78     private static final int[] ADDRESS_FAMILIES =
79             new int[] {AF_INET, AF_INET6};
80 
81     @Parameterized.Parameters
ipSecConfigs()82     public static Collection ipSecConfigs() {
83         return Arrays.asList(
84                 new Object[][] {
85                 {"1.2.3.4", "8.8.4.4", "10.0.1.1/24", AF_INET},
86                 {"2601::2", "2601::10", "2001:db8::1/64", AF_INET6}
87         });
88     }
89 
90     private static final byte[] AEAD_KEY = {
91         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
92         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
93         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
94         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
95         0x73, 0x61, 0x6C, 0x74
96     };
97     private static final byte[] CRYPT_KEY = {
98         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
99         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
100         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
101         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
102     };
103     private static final byte[] AUTH_KEY = {
104         0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
106         0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
108     };
109 
110     AppOpsManager mMockAppOps = mock(AppOpsManager.class);
111 
112     MockContext mMockContext = new MockContext() {
113         @Override
114         public Object getSystemService(String name) {
115             switch(name) {
116                 case Context.APP_OPS_SERVICE:
117                     return mMockAppOps;
118                 default:
119                     return null;
120             }
121         }
122 
123         @Override
124         public PackageManager getPackageManager() {
125             return mMockPkgMgr;
126         }
127 
128         @Override
129         public void enforceCallingOrSelfPermission(String permission, String message) {
130             if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
131                 return;
132             }
133             throw new SecurityException("Unavailable permission requested");
134         }
135     };
136 
137     INetd mMockNetd;
138     PackageManager mMockPkgMgr;
139     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
140     IpSecService mIpSecService;
141     Network fakeNetwork = new Network(0xAB);
142     int mUid = Os.getuid();
143 
144     private static final IpSecAlgorithm AUTH_ALGO =
145             new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
146     private static final IpSecAlgorithm CRYPT_ALGO =
147             new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
148     private static final IpSecAlgorithm AEAD_ALGO =
149             new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
150     private static final int REMOTE_ENCAP_PORT = 4500;
151 
IpSecServiceParameterizedTest( String sourceAddr, String destAddr, String localInnerAddr, int family)152     public IpSecServiceParameterizedTest(
153             String sourceAddr, String destAddr, String localInnerAddr, int family) {
154         mSourceAddr = sourceAddr;
155         mDestinationAddr = destAddr;
156         mLocalInnerAddress = new LinkAddress(localInnerAddr);
157         mFamily = family;
158     }
159 
160     @Before
setUp()161     public void setUp() throws Exception {
162         mMockNetd = mock(INetd.class);
163         mMockPkgMgr = mock(PackageManager.class);
164         mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
165         mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
166 
167         // Injecting mock netd
168         when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
169 
170         // PackageManager should always return true (feature flag tests in IpSecServiceTest)
171         when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
172 
173         // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
174         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
175             .thenReturn(AppOpsManager.MODE_ALLOWED);
176         // A system package will not be granted the app op, so this should fall back to
177         // a permissions check, which should pass.
178         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
179             .thenReturn(AppOpsManager.MODE_DEFAULT);
180         // A mismatch between the package name and the UID will return MODE_IGNORED.
181         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
182             .thenReturn(AppOpsManager.MODE_IGNORED);
183     }
184 
185     //TODO: Add a test to verify SPI.
186 
187     @Test
testIpSecServiceReserveSpi()188     public void testIpSecServiceReserveSpi() throws Exception {
189         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
190                 .thenReturn(TEST_SPI);
191 
192         IpSecSpiResponse spiResp =
193                 mIpSecService.allocateSecurityParameterIndex(
194                         mDestinationAddr, TEST_SPI, new Binder());
195         assertEquals(IpSecManager.Status.OK, spiResp.status);
196         assertEquals(TEST_SPI, spiResp.spi);
197     }
198 
199     @Test
testReleaseSecurityParameterIndex()200     public void testReleaseSecurityParameterIndex() throws Exception {
201         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
202                 .thenReturn(TEST_SPI);
203 
204         IpSecSpiResponse spiResp =
205                 mIpSecService.allocateSecurityParameterIndex(
206                         mDestinationAddr, TEST_SPI, new Binder());
207 
208         mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
209 
210         verify(mMockNetd)
211                 .ipSecDeleteSecurityAssociation(
212                         eq(mUid),
213                         anyString(),
214                         anyString(),
215                         eq(TEST_SPI),
216                         anyInt(),
217                         anyInt(),
218                         anyInt());
219 
220         // Verify quota and RefcountedResource objects cleaned up
221         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
222         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
223         try {
224             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
225             fail("Expected IllegalArgumentException on attempt to access deleted resource");
226         } catch (IllegalArgumentException expected) {
227 
228         }
229     }
230 
231     @Test
testSecurityParameterIndexBinderDeath()232     public void testSecurityParameterIndexBinderDeath() throws Exception {
233         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
234                 .thenReturn(TEST_SPI);
235 
236         IpSecSpiResponse spiResp =
237                 mIpSecService.allocateSecurityParameterIndex(
238                         mDestinationAddr, TEST_SPI, new Binder());
239 
240         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
241         IpSecService.RefcountedResource refcountedRecord =
242                 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
243 
244         refcountedRecord.binderDied();
245 
246         verify(mMockNetd)
247                 .ipSecDeleteSecurityAssociation(
248                         eq(mUid),
249                         anyString(),
250                         anyString(),
251                         eq(TEST_SPI),
252                         anyInt(),
253                         anyInt(),
254                         anyInt());
255 
256         // Verify quota and RefcountedResource objects cleaned up
257         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
258         try {
259             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
260             fail("Expected IllegalArgumentException on attempt to access deleted resource");
261         } catch (IllegalArgumentException expected) {
262 
263         }
264     }
265 
getNewSpiResourceId(String remoteAddress, int returnSpi)266     private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
267         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
268                 .thenReturn(returnSpi);
269 
270         IpSecSpiResponse spi =
271                 mIpSecService.allocateSecurityParameterIndex(
272                         NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
273                         IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
274                         new Binder());
275         return spi.resourceId;
276     }
277 
addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config)278     private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
279         config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
280         config.setSourceAddress(mSourceAddr);
281         config.setDestinationAddress(mDestinationAddr);
282     }
283 
addAuthAndCryptToIpSecConfig(IpSecConfig config)284     private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
285         config.setEncryption(CRYPT_ALGO);
286         config.setAuthentication(AUTH_ALGO);
287     }
288 
addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config)289     private void addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config) throws Exception {
290         config.setEncapType(IpSecTransform.ENCAP_ESPINUDP);
291         config.setEncapSocketResourceId(resourceId);
292         config.setEncapRemotePort(REMOTE_ENCAP_PORT);
293     }
294 
verifyTransformNetdCalledForCreatingSA( IpSecConfig config, IpSecTransformResponse resp)295     private void verifyTransformNetdCalledForCreatingSA(
296             IpSecConfig config, IpSecTransformResponse resp) throws Exception {
297         verifyTransformNetdCalledForCreatingSA(config, resp, 0);
298     }
299 
verifyTransformNetdCalledForCreatingSA( IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort)300     private void verifyTransformNetdCalledForCreatingSA(
301             IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort) throws Exception {
302         IpSecAlgorithm auth = config.getAuthentication();
303         IpSecAlgorithm crypt = config.getEncryption();
304         IpSecAlgorithm authCrypt = config.getAuthenticatedEncryption();
305 
306         verify(mMockNetd, times(1))
307                 .ipSecAddSecurityAssociation(
308                         eq(mUid),
309                         eq(config.getMode()),
310                         eq(config.getSourceAddress()),
311                         eq(config.getDestinationAddress()),
312                         eq((config.getNetwork() != null) ? config.getNetwork().netId : 0),
313                         eq(TEST_SPI),
314                         eq(0),
315                         eq(0),
316                         eq((auth != null) ? auth.getName() : ""),
317                         eq((auth != null) ? auth.getKey() : new byte[] {}),
318                         eq((auth != null) ? auth.getTruncationLengthBits() : 0),
319                         eq((crypt != null) ? crypt.getName() : ""),
320                         eq((crypt != null) ? crypt.getKey() : new byte[] {}),
321                         eq((crypt != null) ? crypt.getTruncationLengthBits() : 0),
322                         eq((authCrypt != null) ? authCrypt.getName() : ""),
323                         eq((authCrypt != null) ? authCrypt.getKey() : new byte[] {}),
324                         eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
325                         eq(config.getEncapType()),
326                         eq(encapSocketPort),
327                         eq(config.getEncapRemotePort()),
328                         eq(config.getXfrmInterfaceId()));
329     }
330 
331     @Test
testCreateTransform()332     public void testCreateTransform() throws Exception {
333         IpSecConfig ipSecConfig = new IpSecConfig();
334         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
335         addAuthAndCryptToIpSecConfig(ipSecConfig);
336 
337         IpSecTransformResponse createTransformResp =
338                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
339         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
340 
341         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
342     }
343 
344     @Test
testCreateTransformAead()345     public void testCreateTransformAead() throws Exception {
346         IpSecConfig ipSecConfig = new IpSecConfig();
347         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
348 
349         ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
350 
351         IpSecTransformResponse createTransformResp =
352                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
353         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
354 
355         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
356     }
357 
358     @Test
testCreateTransportModeTransformWithEncap()359     public void testCreateTransportModeTransformWithEncap() throws Exception {
360         IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
361 
362         IpSecConfig ipSecConfig = new IpSecConfig();
363         ipSecConfig.setMode(IpSecTransform.MODE_TRANSPORT);
364         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
365         addAuthAndCryptToIpSecConfig(ipSecConfig);
366         addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
367 
368         if (mFamily == AF_INET) {
369             IpSecTransformResponse createTransformResp =
370                     mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
371             assertEquals(IpSecManager.Status.OK, createTransformResp.status);
372 
373             verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
374         } else {
375             try {
376                 IpSecTransformResponse createTransformResp =
377                         mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
378                 fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
379             } catch (IllegalArgumentException expected) {
380             }
381         }
382     }
383 
384     @Test
testCreateTunnelModeTransformWithEncap()385     public void testCreateTunnelModeTransformWithEncap() throws Exception {
386         IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
387 
388         IpSecConfig ipSecConfig = new IpSecConfig();
389         ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
390         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
391         addAuthAndCryptToIpSecConfig(ipSecConfig);
392         addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
393 
394         if (mFamily == AF_INET) {
395             IpSecTransformResponse createTransformResp =
396                     mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
397             assertEquals(IpSecManager.Status.OK, createTransformResp.status);
398 
399             verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
400         } else {
401             try {
402                 IpSecTransformResponse createTransformResp =
403                         mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
404                 fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
405             } catch (IllegalArgumentException expected) {
406             }
407         }
408     }
409 
410     @Test
testCreateTwoTransformsWithSameSpis()411     public void testCreateTwoTransformsWithSameSpis() throws Exception {
412         IpSecConfig ipSecConfig = new IpSecConfig();
413         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
414         addAuthAndCryptToIpSecConfig(ipSecConfig);
415 
416         IpSecTransformResponse createTransformResp =
417                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
418         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
419 
420         // Attempting to create transform a second time with the same SPIs should throw an error...
421         try {
422                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
423                 fail("IpSecService should have thrown an error for reuse of SPI");
424         } catch (IllegalStateException expected) {
425         }
426 
427         // ... even if the transform is deleted
428         mIpSecService.deleteTransform(createTransformResp.resourceId);
429         try {
430                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
431                 fail("IpSecService should have thrown an error for reuse of SPI");
432         } catch (IllegalStateException expected) {
433         }
434     }
435 
436     @Test
testReleaseOwnedSpi()437     public void testReleaseOwnedSpi() throws Exception {
438         IpSecConfig ipSecConfig = new IpSecConfig();
439         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
440         addAuthAndCryptToIpSecConfig(ipSecConfig);
441 
442         IpSecTransformResponse createTransformResp =
443                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
444         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
445         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
446         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
447         verify(mMockNetd, times(0))
448                 .ipSecDeleteSecurityAssociation(
449                         eq(mUid),
450                         anyString(),
451                         anyString(),
452                         eq(TEST_SPI),
453                         anyInt(),
454                         anyInt(),
455                         anyInt());
456         // quota is not released until the SPI is released by the Transform
457         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
458     }
459 
460     @Test
testDeleteTransform()461     public void testDeleteTransform() throws Exception {
462         IpSecConfig ipSecConfig = new IpSecConfig();
463         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
464         addAuthAndCryptToIpSecConfig(ipSecConfig);
465 
466         IpSecTransformResponse createTransformResp =
467                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
468         mIpSecService.deleteTransform(createTransformResp.resourceId);
469 
470         verify(mMockNetd, times(1))
471                 .ipSecDeleteSecurityAssociation(
472                         eq(mUid),
473                         anyString(),
474                         anyString(),
475                         eq(TEST_SPI),
476                         anyInt(),
477                         anyInt(),
478                         anyInt());
479 
480         // Verify quota and RefcountedResource objects cleaned up
481         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
482         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
483         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
484 
485         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
486         // Verify that ipSecDeleteSa was not called when the SPI was released because the
487         // ownedByTransform property should prevent it; (note, the called count is cumulative).
488         verify(mMockNetd, times(1))
489                 .ipSecDeleteSecurityAssociation(
490                         anyInt(),
491                         anyString(),
492                         anyString(),
493                         anyInt(),
494                         anyInt(),
495                         anyInt(),
496                         anyInt());
497         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
498 
499         try {
500             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
501                     createTransformResp.resourceId);
502             fail("Expected IllegalArgumentException on attempt to access deleted resource");
503         } catch (IllegalArgumentException expected) {
504 
505         }
506     }
507 
508     @Test
testTransportModeTransformBinderDeath()509     public void testTransportModeTransformBinderDeath() throws Exception {
510         IpSecConfig ipSecConfig = new IpSecConfig();
511         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
512         addAuthAndCryptToIpSecConfig(ipSecConfig);
513 
514         IpSecTransformResponse createTransformResp =
515                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
516 
517         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
518         IpSecService.RefcountedResource refcountedRecord =
519                 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
520                         createTransformResp.resourceId);
521 
522         refcountedRecord.binderDied();
523 
524         verify(mMockNetd)
525                 .ipSecDeleteSecurityAssociation(
526                         eq(mUid),
527                         anyString(),
528                         anyString(),
529                         eq(TEST_SPI),
530                         anyInt(),
531                         anyInt(),
532                         anyInt());
533 
534         // Verify quota and RefcountedResource objects cleaned up
535         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
536         try {
537             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
538                     createTransformResp.resourceId);
539             fail("Expected IllegalArgumentException on attempt to access deleted resource");
540         } catch (IllegalArgumentException expected) {
541 
542         }
543     }
544 
545     @Test
testApplyTransportModeTransform()546     public void testApplyTransportModeTransform() throws Exception {
547         IpSecConfig ipSecConfig = new IpSecConfig();
548         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
549         addAuthAndCryptToIpSecConfig(ipSecConfig);
550 
551         IpSecTransformResponse createTransformResp =
552                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
553 
554         Socket socket = new Socket();
555         socket.bind(null);
556         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
557 
558         int resourceId = createTransformResp.resourceId;
559         mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
560 
561         verify(mMockNetd)
562                 .ipSecApplyTransportModeTransform(
563                         eq(pfd),
564                         eq(mUid),
565                         eq(IpSecManager.DIRECTION_OUT),
566                         anyString(),
567                         anyString(),
568                         eq(TEST_SPI));
569     }
570 
571     @Test
testRemoveTransportModeTransform()572     public void testRemoveTransportModeTransform() throws Exception {
573         Socket socket = new Socket();
574         socket.bind(null);
575         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
576         mIpSecService.removeTransportModeTransforms(pfd);
577 
578         verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
579     }
580 
createAndValidateTunnel( String localAddr, String remoteAddr, String pkgName)581     private IpSecTunnelInterfaceResponse createAndValidateTunnel(
582             String localAddr, String remoteAddr, String pkgName) {
583         IpSecTunnelInterfaceResponse createTunnelResp =
584                 mIpSecService.createTunnelInterface(
585                         mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
586 
587         assertNotNull(createTunnelResp);
588         assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
589         return createTunnelResp;
590     }
591 
592     @Test
testCreateTunnelInterface()593     public void testCreateTunnelInterface() throws Exception {
594         IpSecTunnelInterfaceResponse createTunnelResp =
595                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
596 
597         // Check that we have stored the tracking object, and retrieve it
598         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
599         IpSecService.RefcountedResource refcountedRecord =
600                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
601                         createTunnelResp.resourceId);
602 
603         assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
604         verify(mMockNetd)
605                 .ipSecAddTunnelInterface(
606                         eq(createTunnelResp.interfaceName),
607                         eq(mSourceAddr),
608                         eq(mDestinationAddr),
609                         anyInt(),
610                         anyInt(),
611                         anyInt());
612     }
613 
614     @Test
testDeleteTunnelInterface()615     public void testDeleteTunnelInterface() throws Exception {
616         IpSecTunnelInterfaceResponse createTunnelResp =
617                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
618 
619         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
620 
621         mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
622 
623         // Verify quota and RefcountedResource objects cleaned up
624         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
625         verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
626         try {
627             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
628                     createTunnelResp.resourceId);
629             fail("Expected IllegalArgumentException on attempt to access deleted resource");
630         } catch (IllegalArgumentException expected) {
631         }
632     }
633 
634     @Test
testTunnelInterfaceBinderDeath()635     public void testTunnelInterfaceBinderDeath() throws Exception {
636         IpSecTunnelInterfaceResponse createTunnelResp =
637                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
638 
639         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
640         IpSecService.RefcountedResource refcountedRecord =
641                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
642                         createTunnelResp.resourceId);
643 
644         refcountedRecord.binderDied();
645 
646         // Verify quota and RefcountedResource objects cleaned up
647         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
648         verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
649         try {
650             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
651                     createTunnelResp.resourceId);
652             fail("Expected IllegalArgumentException on attempt to access deleted resource");
653         } catch (IllegalArgumentException expected) {
654         }
655     }
656 
657     @Test
testApplyTunnelModeTransform()658     public void testApplyTunnelModeTransform() throws Exception {
659         IpSecConfig ipSecConfig = new IpSecConfig();
660         ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
661         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
662         addAuthAndCryptToIpSecConfig(ipSecConfig);
663 
664         IpSecTransformResponse createTransformResp =
665                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
666         IpSecTunnelInterfaceResponse createTunnelResp =
667                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
668 
669         int transformResourceId = createTransformResp.resourceId;
670         int tunnelResourceId = createTunnelResp.resourceId;
671         mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
672                 transformResourceId, "blessedPackage");
673 
674         for (int selAddrFamily : ADDRESS_FAMILIES) {
675             verify(mMockNetd)
676                     .ipSecUpdateSecurityPolicy(
677                             eq(mUid),
678                             eq(selAddrFamily),
679                             eq(IpSecManager.DIRECTION_OUT),
680                             anyString(),
681                             anyString(),
682                             eq(TEST_SPI),
683                             anyInt(), // iKey/oKey
684                             anyInt(), // mask
685                             eq(tunnelResourceId));
686         }
687 
688         ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
689         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
690     }
691 
692     @Test
testAddRemoveAddressFromTunnelInterface()693     public void testAddRemoveAddressFromTunnelInterface() throws Exception {
694         for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
695             IpSecTunnelInterfaceResponse createTunnelResp =
696                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
697             mIpSecService.addAddressToTunnelInterface(
698                     createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
699             verify(mMockNetd, times(1))
700                     .interfaceAddAddress(
701                             eq(createTunnelResp.interfaceName),
702                             eq(mLocalInnerAddress.getAddress().getHostAddress()),
703                             eq(mLocalInnerAddress.getPrefixLength()));
704             mIpSecService.removeAddressFromTunnelInterface(
705                     createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
706             verify(mMockNetd, times(1))
707                     .interfaceDelAddress(
708                             eq(createTunnelResp.interfaceName),
709                             eq(mLocalInnerAddress.getAddress().getHostAddress()),
710                             eq(mLocalInnerAddress.getPrefixLength()));
711             mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
712         }
713     }
714 
715     @Ignore
716     @Test
testAddTunnelFailsForBadPackageName()717     public void testAddTunnelFailsForBadPackageName() throws Exception {
718         try {
719             IpSecTunnelInterfaceResponse createTunnelResp =
720                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
721             fail("Expected a SecurityException for badPackage.");
722         } catch (SecurityException expected) {
723         }
724     }
725 
726     @Test
testFeatureFlagVerification()727     public void testFeatureFlagVerification() throws Exception {
728         when(mMockPkgMgr.hasSystemFeature(eq(PackageManager.FEATURE_IPSEC_TUNNELS)))
729                 .thenReturn(false);
730 
731         try {
732             String addr = Inet4Address.getLoopbackAddress().getHostAddress();
733             mIpSecService.createTunnelInterface(
734                     addr, addr, new Network(0), new Binder(), "blessedPackage");
735             fail("Expected UnsupportedOperationException for disabled feature");
736         } catch (UnsupportedOperationException expected) {
737         }
738     }
739 }
740