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