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