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