blob: 66e0955b04c36f16fc45f171bf5041e68b00b79f [file] [log] [blame]
Nathan Harold2e9a5202017-09-26 11:44:23 -07001/*
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
17package com.android.server;
18
19import static org.junit.Assert.assertEquals;
Benedict Wong0febe5e2017-08-22 21:42:33 -070020import static org.junit.Assert.fail;
Nathan Harold2e9a5202017-09-26 11:44:23 -070021import static org.mockito.Matchers.anyInt;
Nathan Harold2e9a5202017-09-26 11:44:23 -070022import static org.mockito.Matchers.anyString;
23import static org.mockito.Matchers.eq;
24import static org.mockito.Mockito.mock;
25import static org.mockito.Mockito.verify;
26import static org.mockito.Mockito.when;
27
28import android.content.Context;
29import android.net.INetd;
30import android.net.IpSecAlgorithm;
31import android.net.IpSecConfig;
32import android.net.IpSecManager;
33import android.net.IpSecSpiResponse;
Nathan Harold2e9a5202017-09-26 11:44:23 -070034import android.net.IpSecTransformResponse;
35import android.net.NetworkUtils;
36import android.os.Binder;
37import android.os.ParcelFileDescriptor;
38import android.support.test.filters.SmallTest;
Benedict Wong344bd622017-11-16 15:27:22 -080039import android.system.Os;
Nathan Harold2e9a5202017-09-26 11:44:23 -070040
41import java.net.Socket;
42import java.util.Arrays;
43import java.util.Collection;
44
45import org.junit.Before;
46import org.junit.Test;
47import org.junit.runner.RunWith;
48import org.junit.runners.Parameterized;
49
50/** Unit tests for {@link IpSecService}. */
51@SmallTest
52@RunWith(Parameterized.class)
53public class IpSecServiceParameterizedTest {
54
Nathan Harolda2523312018-01-05 19:25:13 -080055 private static final int TEST_SPI = 0xD1201D;
Nathan Harold2e9a5202017-09-26 11:44:23 -070056
Nathan Harolda2523312018-01-05 19:25:13 -080057 private final String mDestinationAddr;
Nathan Harold5676f5f2018-01-16 19:34:01 -080058 private final String mSourceAddr;
Nathan Harold2e9a5202017-09-26 11:44:23 -070059
60 @Parameterized.Parameters
61 public static Collection ipSecConfigs() {
Nathan Harold5676f5f2018-01-16 19:34:01 -080062 return Arrays.asList(new Object[][] {{"1.2.3.4", "8.8.4.4"}, {"2601::2", "2601::10"}});
Nathan Harold2e9a5202017-09-26 11:44:23 -070063 }
64
Benedict Wong4ebc2c52017-11-01 17:14:25 -070065 private static final byte[] AEAD_KEY = {
66 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
67 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
68 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
69 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
70 0x73, 0x61, 0x6C, 0x74
71 };
Nathan Harold2e9a5202017-09-26 11:44:23 -070072 private static final byte[] CRYPT_KEY = {
73 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
74 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
75 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
76 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
77 };
78 private static final byte[] AUTH_KEY = {
79 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
81 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
83 };
84
85 Context mMockContext;
86 INetd mMockNetd;
87 IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
88 IpSecService mIpSecService;
89
Benedict Wong0febe5e2017-08-22 21:42:33 -070090 private static final IpSecAlgorithm AUTH_ALGO =
91 new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
92 private static final IpSecAlgorithm CRYPT_ALGO =
93 new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
94 private static final IpSecAlgorithm AEAD_ALGO =
Benedict Wong4ebc2c52017-11-01 17:14:25 -070095 new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
Benedict Wong0febe5e2017-08-22 21:42:33 -070096
Nathan Harold5676f5f2018-01-16 19:34:01 -080097 public IpSecServiceParameterizedTest(String sourceAddr, String destAddr) {
98 mSourceAddr = sourceAddr;
99 mDestinationAddr = destAddr;
Nathan Harold2e9a5202017-09-26 11:44:23 -0700100 }
101
102 @Before
103 public void setUp() throws Exception {
104 mMockContext = mock(Context.class);
105 mMockNetd = mock(INetd.class);
106 mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
107 mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
108
109 // Injecting mock netd
110 when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
111 }
112
113 @Test
114 public void testIpSecServiceReserveSpi() throws Exception {
Nathan Harolda2523312018-01-05 19:25:13 -0800115 when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
116 .thenReturn(TEST_SPI);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700117
118 IpSecSpiResponse spiResp =
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800119 mIpSecService.allocateSecurityParameterIndex(
Nathan Harolda2523312018-01-05 19:25:13 -0800120 mDestinationAddr, TEST_SPI, new Binder());
Nathan Harold2e9a5202017-09-26 11:44:23 -0700121 assertEquals(IpSecManager.Status.OK, spiResp.status);
Nathan Harolda2523312018-01-05 19:25:13 -0800122 assertEquals(TEST_SPI, spiResp.spi);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700123 }
124
125 @Test
126 public void testReleaseSecurityParameterIndex() throws Exception {
Nathan Harolda2523312018-01-05 19:25:13 -0800127 when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
128 .thenReturn(TEST_SPI);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700129
130 IpSecSpiResponse spiResp =
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800131 mIpSecService.allocateSecurityParameterIndex(
Nathan Harolda2523312018-01-05 19:25:13 -0800132 mDestinationAddr, TEST_SPI, new Binder());
Nathan Harold2e9a5202017-09-26 11:44:23 -0700133
134 mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
135
136 verify(mMockNetd)
137 .ipSecDeleteSecurityAssociation(
Di Lu0b611f42018-01-11 11:35:25 -0800138 eq(spiResp.resourceId),
139 anyString(),
140 anyString(),
141 eq(TEST_SPI),
142 anyInt(),
143 anyInt());
Benedict Wong344bd622017-11-16 15:27:22 -0800144
145 // Verify quota and RefcountedResource objects cleaned up
146 IpSecService.UserRecord userRecord =
147 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
148 assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
149 try {
150 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
151 fail("Expected IllegalArgumentException on attempt to access deleted resource");
152 } catch (IllegalArgumentException expected) {
153
154 }
155 }
156
157 @Test
158 public void testSecurityParameterIndexBinderDeath() throws Exception {
Nathan Harolda2523312018-01-05 19:25:13 -0800159 when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
160 .thenReturn(TEST_SPI);
Benedict Wong344bd622017-11-16 15:27:22 -0800161
162 IpSecSpiResponse spiResp =
Nathan Harold660a3352017-12-14 14:46:46 -0800163 mIpSecService.allocateSecurityParameterIndex(
Nathan Harolda2523312018-01-05 19:25:13 -0800164 mDestinationAddr, TEST_SPI, new Binder());
Benedict Wong344bd622017-11-16 15:27:22 -0800165
166 IpSecService.UserRecord userRecord =
167 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
168 IpSecService.RefcountedResource refcountedRecord =
169 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
170
171 refcountedRecord.binderDied();
172
173 verify(mMockNetd)
174 .ipSecDeleteSecurityAssociation(
Di Lu0b611f42018-01-11 11:35:25 -0800175 eq(spiResp.resourceId),
176 anyString(),
177 anyString(),
178 eq(TEST_SPI),
179 anyInt(),
180 anyInt());
Benedict Wong344bd622017-11-16 15:27:22 -0800181
182 // Verify quota and RefcountedResource objects cleaned up
183 assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
184 try {
185 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
186 fail("Expected IllegalArgumentException on attempt to access deleted resource");
187 } catch (IllegalArgumentException expected) {
188
189 }
Nathan Harold2e9a5202017-09-26 11:44:23 -0700190 }
191
Nathan Harolda2523312018-01-05 19:25:13 -0800192 private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
193 when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
Benedict Wong0febe5e2017-08-22 21:42:33 -0700194 .thenReturn(returnSpi);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700195
Benedict Wong0febe5e2017-08-22 21:42:33 -0700196 IpSecSpiResponse spi =
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800197 mIpSecService.allocateSecurityParameterIndex(
Benedict Wong0febe5e2017-08-22 21:42:33 -0700198 NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
199 IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
200 new Binder());
201 return spi.resourceId;
202 }
Nathan Harold2e9a5202017-09-26 11:44:23 -0700203
Benedict Wong0febe5e2017-08-22 21:42:33 -0700204 private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
Nathan Harolda2523312018-01-05 19:25:13 -0800205 config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
Nathan Harold5676f5f2018-01-16 19:34:01 -0800206 config.setSourceAddress(mSourceAddr);
Nathan Harolda2523312018-01-05 19:25:13 -0800207 config.setDestinationAddress(mDestinationAddr);
Benedict Wong0febe5e2017-08-22 21:42:33 -0700208 }
209
210 private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
Nathan Harolda2523312018-01-05 19:25:13 -0800211 config.setEncryption(CRYPT_ALGO);
212 config.setAuthentication(AUTH_ALGO);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700213 }
214
215 @Test
Benedict Wongf33f03132018-01-18 14:38:16 -0800216 public void testCreateTransform() throws Exception {
Benedict Wong0febe5e2017-08-22 21:42:33 -0700217 IpSecConfig ipSecConfig = new IpSecConfig();
218 addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
219 addAuthAndCryptToIpSecConfig(ipSecConfig);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700220
221 IpSecTransformResponse createTransformResp =
Benedict Wongf33f03132018-01-18 14:38:16 -0800222 mIpSecService.createTransform(ipSecConfig, new Binder());
Nathan Harold2e9a5202017-09-26 11:44:23 -0700223 assertEquals(IpSecManager.Status.OK, createTransformResp.status);
224
225 verify(mMockNetd)
226 .ipSecAddSecurityAssociation(
227 eq(createTransformResp.resourceId),
228 anyInt(),
Nathan Harold2e9a5202017-09-26 11:44:23 -0700229 anyString(),
230 anyString(),
Benedict Wong0fe58a92018-01-19 17:36:02 -0800231 anyInt(),
Nathan Harolda2523312018-01-05 19:25:13 -0800232 eq(TEST_SPI),
Di Lu0b611f42018-01-11 11:35:25 -0800233 anyInt(),
234 anyInt(),
Benedict Wong0febe5e2017-08-22 21:42:33 -0700235 eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
236 eq(AUTH_KEY),
237 anyInt(),
238 eq(IpSecAlgorithm.CRYPT_AES_CBC),
239 eq(CRYPT_KEY),
240 anyInt(),
241 eq(""),
Manoj Boopathi Rajfffa8112017-10-26 11:49:02 -0700242 eq(new byte[] {}),
Benedict Wong0febe5e2017-08-22 21:42:33 -0700243 eq(0),
244 anyInt(),
245 anyInt(),
246 anyInt());
247 }
248
249 @Test
Benedict Wongf33f03132018-01-18 14:38:16 -0800250 public void testCreateTransformAead() throws Exception {
Benedict Wong0febe5e2017-08-22 21:42:33 -0700251 IpSecConfig ipSecConfig = new IpSecConfig();
252 addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
253
Nathan Harolda2523312018-01-05 19:25:13 -0800254 ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
Benedict Wong0febe5e2017-08-22 21:42:33 -0700255
256 IpSecTransformResponse createTransformResp =
Benedict Wongf33f03132018-01-18 14:38:16 -0800257 mIpSecService.createTransform(ipSecConfig, new Binder());
Benedict Wong0febe5e2017-08-22 21:42:33 -0700258 assertEquals(IpSecManager.Status.OK, createTransformResp.status);
259
260 verify(mMockNetd)
261 .ipSecAddSecurityAssociation(
262 eq(createTransformResp.resourceId),
263 anyInt(),
Benedict Wong0febe5e2017-08-22 21:42:33 -0700264 anyString(),
265 anyString(),
Benedict Wong0fe58a92018-01-19 17:36:02 -0800266 anyInt(),
Nathan Harolda2523312018-01-05 19:25:13 -0800267 eq(TEST_SPI),
Di Lu0b611f42018-01-11 11:35:25 -0800268 anyInt(),
269 anyInt(),
Benedict Wong0febe5e2017-08-22 21:42:33 -0700270 eq(""),
Manoj Boopathi Rajfffa8112017-10-26 11:49:02 -0700271 eq(new byte[] {}),
Benedict Wong0febe5e2017-08-22 21:42:33 -0700272 eq(0),
273 eq(""),
Manoj Boopathi Rajfffa8112017-10-26 11:49:02 -0700274 eq(new byte[] {}),
Benedict Wong0febe5e2017-08-22 21:42:33 -0700275 eq(0),
276 eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
Benedict Wong4ebc2c52017-11-01 17:14:25 -0700277 eq(AEAD_KEY),
Nathan Harold2e9a5202017-09-26 11:44:23 -0700278 anyInt(),
279 anyInt(),
280 anyInt(),
281 anyInt());
282 }
283
Benedict Wonge6b42772017-12-13 18:26:40 -0800284 public void testCreateTwoTransformsWithSameSpis() throws Exception {
285 IpSecConfig ipSecConfig = new IpSecConfig();
286 addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
287 addAuthAndCryptToIpSecConfig(ipSecConfig);
288
289 IpSecTransformResponse createTransformResp =
290 mIpSecService.createTransform(ipSecConfig, new Binder());
291 assertEquals(IpSecManager.Status.OK, createTransformResp.status);
292
293 // Attempting to create transform a second time with the same SPIs should throw an error...
294 try {
295 mIpSecService.createTransform(ipSecConfig, new Binder());
296 fail("IpSecService should have thrown an error for reuse of SPI");
297 } catch (IllegalStateException expected) {
298 }
299
300 // ... even if the transform is deleted
301 mIpSecService.deleteTransform(createTransformResp.resourceId);
302 try {
303 mIpSecService.createTransform(ipSecConfig, new Binder());
304 fail("IpSecService should have thrown an error for reuse of SPI");
305 } catch (IllegalStateException expected) {
306 }
307 }
308
Nathan Harold2e9a5202017-09-26 11:44:23 -0700309 @Test
Benedict Wongf33f03132018-01-18 14:38:16 -0800310 public void testDeleteTransform() throws Exception {
Benedict Wong0febe5e2017-08-22 21:42:33 -0700311 IpSecConfig ipSecConfig = new IpSecConfig();
312 addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
313 addAuthAndCryptToIpSecConfig(ipSecConfig);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700314
315 IpSecTransformResponse createTransformResp =
Benedict Wongf33f03132018-01-18 14:38:16 -0800316 mIpSecService.createTransform(ipSecConfig, new Binder());
317 mIpSecService.deleteTransform(createTransformResp.resourceId);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700318
319 verify(mMockNetd)
320 .ipSecDeleteSecurityAssociation(
Di Lu0b611f42018-01-11 11:35:25 -0800321 eq(createTransformResp.resourceId),
322 anyString(),
323 anyString(),
324 eq(TEST_SPI),
325 anyInt(),
326 anyInt());
Benedict Wong344bd622017-11-16 15:27:22 -0800327
328 // Verify quota and RefcountedResource objects cleaned up
329 IpSecService.UserRecord userRecord =
330 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
331 assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
332 try {
333 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
334 createTransformResp.resourceId);
335 fail("Expected IllegalArgumentException on attempt to access deleted resource");
336 } catch (IllegalArgumentException expected) {
337
338 }
339 }
340
341 @Test
342 public void testTransportModeTransformBinderDeath() throws Exception {
343 IpSecConfig ipSecConfig = new IpSecConfig();
344 addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
345 addAuthAndCryptToIpSecConfig(ipSecConfig);
346
347 IpSecTransformResponse createTransformResp =
Benedict Wongf33f03132018-01-18 14:38:16 -0800348 mIpSecService.createTransform(ipSecConfig, new Binder());
Benedict Wong344bd622017-11-16 15:27:22 -0800349
350 IpSecService.UserRecord userRecord =
351 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
352 IpSecService.RefcountedResource refcountedRecord =
353 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
354 createTransformResp.resourceId);
355
356 refcountedRecord.binderDied();
357
358 verify(mMockNetd)
359 .ipSecDeleteSecurityAssociation(
Di Lu0b611f42018-01-11 11:35:25 -0800360 eq(createTransformResp.resourceId),
361 anyString(),
362 anyString(),
363 eq(TEST_SPI),
364 anyInt(),
365 anyInt());
Benedict Wong344bd622017-11-16 15:27:22 -0800366
367 // Verify quota and RefcountedResource objects cleaned up
368 assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
369 try {
370 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
371 createTransformResp.resourceId);
372 fail("Expected IllegalArgumentException on attempt to access deleted resource");
373 } catch (IllegalArgumentException expected) {
374
375 }
Nathan Harold2e9a5202017-09-26 11:44:23 -0700376 }
377
378 @Test
379 public void testApplyTransportModeTransform() throws Exception {
Benedict Wong0febe5e2017-08-22 21:42:33 -0700380 IpSecConfig ipSecConfig = new IpSecConfig();
381 addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
382 addAuthAndCryptToIpSecConfig(ipSecConfig);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700383
384 IpSecTransformResponse createTransformResp =
Benedict Wongf33f03132018-01-18 14:38:16 -0800385 mIpSecService.createTransform(ipSecConfig, new Binder());
Nathan Harold2e9a5202017-09-26 11:44:23 -0700386 ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
387
388 int resourceId = createTransformResp.resourceId;
Nathan Harolda2523312018-01-05 19:25:13 -0800389 mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700390
391 verify(mMockNetd)
392 .ipSecApplyTransportModeTransform(
393 eq(pfd.getFileDescriptor()),
394 eq(resourceId),
Nathan Harolda2523312018-01-05 19:25:13 -0800395 eq(IpSecManager.DIRECTION_OUT),
Nathan Harold2e9a5202017-09-26 11:44:23 -0700396 anyString(),
397 anyString(),
Nathan Harolda2523312018-01-05 19:25:13 -0800398 eq(TEST_SPI));
Nathan Harold2e9a5202017-09-26 11:44:23 -0700399 }
400
401 @Test
402 public void testRemoveTransportModeTransform() throws Exception {
403 ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
Nathan Haroldf73d2522018-01-17 01:00:20 -0800404 mIpSecService.removeTransportModeTransforms(pfd);
Nathan Harold2e9a5202017-09-26 11:44:23 -0700405
406 verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
407 }
408}