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