Home | History | Annotate | Download | only in server
      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
     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 
    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
    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
    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
    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
    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 
    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 
    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 
    284     private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
    285         config.setEncryption(CRYPT_ALGO);
    286         config.setAuthentication(AUTH_ALGO);
    287     }
    288 
    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 
    295     private void verifyTransformNetdCalledForCreatingSA(
    296             IpSecConfig config, IpSecTransformResponse resp) throws Exception {
    297         verifyTransformNetdCalledForCreatingSA(config, resp, 0);
    298     }
    299 
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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
    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
    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
    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
    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
    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
    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
    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