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