blob: 8559c2080abbac23e74c05eff397158f8d005999 [file] [log] [blame]
Benedict Wong56420432019-11-01 16:45:08 -07001/*
2 * Copyright (C) 2019 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 android.net;
18
Chiachang Wang137bbed2022-02-11 15:32:30 +080019import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
20
Benedict Wong56420432019-11-01 16:45:08 -070021import static org.junit.Assert.assertArrayEquals;
22import static org.junit.Assert.assertEquals;
23import static org.junit.Assert.assertNotNull;
24import static org.junit.Assert.assertNull;
25import static org.junit.Assert.assertTrue;
26import static org.junit.Assert.fail;
Benedict Wong56420432019-11-01 16:45:08 -070027
Remi NGUYEN VAN154cf1d2021-06-29 17:16:28 +090028import android.os.Build;
Benedict Wong56420432019-11-01 16:45:08 -070029import android.test.mock.MockContext;
30
31import androidx.test.filters.SmallTest;
Benedict Wong56420432019-11-01 16:45:08 -070032
33import com.android.internal.net.VpnProfile;
Daulet Zhanguzin9a357a92021-01-25 19:43:53 +000034import com.android.internal.org.bouncycastle.x509.X509V1CertificateGenerator;
Yan Yan86783c32021-04-28 15:16:22 -070035import com.android.net.module.util.ProxyUtils;
Remi NGUYEN VAN154cf1d2021-06-29 17:16:28 +090036import com.android.testutils.DevSdkIgnoreRule;
37import com.android.testutils.DevSdkIgnoreRunner;
Benedict Wong56420432019-11-01 16:45:08 -070038
39import org.junit.Before;
Chiachang Wangaf7c44c2022-01-18 19:19:25 +080040import org.junit.Rule;
Benedict Wong56420432019-11-01 16:45:08 -070041import org.junit.Test;
42import org.junit.runner.RunWith;
43
44import java.math.BigInteger;
45import java.security.KeyPair;
46import java.security.KeyPairGenerator;
47import java.security.PrivateKey;
48import java.security.cert.X509Certificate;
Benedict Wong8e3914c2020-04-09 21:49:05 -070049import java.util.ArrayList;
50import java.util.Arrays;
Benedict Wong56420432019-11-01 16:45:08 -070051import java.util.Date;
Benedict Wong8e3914c2020-04-09 21:49:05 -070052import java.util.List;
Benedict Wong56420432019-11-01 16:45:08 -070053import java.util.concurrent.TimeUnit;
54
55import javax.security.auth.x500.X500Principal;
56
57/** Unit tests for {@link Ikev2VpnProfile.Builder}. */
58@SmallTest
Remi NGUYEN VAN154cf1d2021-06-29 17:16:28 +090059@RunWith(DevSdkIgnoreRunner.class)
60@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
Benedict Wong56420432019-11-01 16:45:08 -070061public class Ikev2VpnProfileTest {
62 private static final String SERVER_ADDR_STRING = "1.2.3.4";
63 private static final String IDENTITY_STRING = "Identity";
64 private static final String USERNAME_STRING = "username";
65 private static final String PASSWORD_STRING = "pa55w0rd";
66 private static final String EXCL_LIST = "exclList";
67 private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
68 private static final int TEST_MTU = 1300;
69
Chiachang Wangaf7c44c2022-01-18 19:19:25 +080070 @Rule
71 public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
72
Benedict Wong56420432019-11-01 16:45:08 -070073 private final MockContext mMockContext =
74 new MockContext() {
75 @Override
76 public String getOpPackageName() {
77 return "fooPackage";
78 }
79 };
Serik Beketayeva9dc6772020-12-06 23:08:08 -080080 private final ProxyInfo mProxy = ProxyInfo.buildDirectProxy(
81 SERVER_ADDR_STRING, -1, ProxyUtils.exclusionStringAsList(EXCL_LIST));
Benedict Wong56420432019-11-01 16:45:08 -070082
83 private X509Certificate mUserCert;
84 private X509Certificate mServerRootCa;
85 private PrivateKey mPrivateKey;
86
87 @Before
88 public void setUp() throws Exception {
89 mServerRootCa = generateRandomCertAndKeyPair().cert;
90
91 final CertificateAndKey userCertKey = generateRandomCertAndKeyPair();
92 mUserCert = userCertKey.cert;
93 mPrivateKey = userCertKey.key;
94 }
95
96 private Ikev2VpnProfile.Builder getBuilderWithDefaultOptions() {
97 final Ikev2VpnProfile.Builder builder =
98 new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING);
99
100 builder.setBypassable(true);
101 builder.setProxy(mProxy);
102 builder.setMaxMtu(TEST_MTU);
103 builder.setMetered(true);
104
105 return builder;
106 }
107
108 @Test
109 public void testBuildValidProfileWithOptions() throws Exception {
110 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
111
112 builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
113 final Ikev2VpnProfile profile = builder.build();
114 assertNotNull(profile);
115
116 // Check non-auth parameters correctly stored
117 assertEquals(SERVER_ADDR_STRING, profile.getServerAddr());
118 assertEquals(IDENTITY_STRING, profile.getUserIdentity());
119 assertEquals(mProxy, profile.getProxyInfo());
120 assertTrue(profile.isBypassable());
121 assertTrue(profile.isMetered());
122 assertEquals(TEST_MTU, profile.getMaxMtu());
Benedict Wong8e3914c2020-04-09 21:49:05 -0700123 assertEquals(Ikev2VpnProfile.DEFAULT_ALGORITHMS, profile.getAllowedAlgorithms());
Benedict Wong56420432019-11-01 16:45:08 -0700124 }
125
126 @Test
127 public void testBuildUsernamePasswordProfile() throws Exception {
128 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
129
130 builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
131 final Ikev2VpnProfile profile = builder.build();
132 assertNotNull(profile);
133
134 assertEquals(USERNAME_STRING, profile.getUsername());
135 assertEquals(PASSWORD_STRING, profile.getPassword());
136 assertEquals(mServerRootCa, profile.getServerRootCaCert());
137
138 assertNull(profile.getPresharedKey());
139 assertNull(profile.getRsaPrivateKey());
140 assertNull(profile.getUserCert());
141 }
142
143 @Test
144 public void testBuildDigitalSignatureProfile() throws Exception {
145 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
146
147 builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
148 final Ikev2VpnProfile profile = builder.build();
149 assertNotNull(profile);
150
151 assertEquals(profile.getUserCert(), mUserCert);
152 assertEquals(mPrivateKey, profile.getRsaPrivateKey());
153 assertEquals(profile.getServerRootCaCert(), mServerRootCa);
154
155 assertNull(profile.getPresharedKey());
156 assertNull(profile.getUsername());
157 assertNull(profile.getPassword());
158 }
159
160 @Test
161 public void testBuildPresharedKeyProfile() throws Exception {
162 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
163
164 builder.setAuthPsk(PSK_BYTES);
165 final Ikev2VpnProfile profile = builder.build();
166 assertNotNull(profile);
167
168 assertArrayEquals(PSK_BYTES, profile.getPresharedKey());
169
170 assertNull(profile.getServerRootCaCert());
171 assertNull(profile.getUsername());
172 assertNull(profile.getPassword());
173 assertNull(profile.getRsaPrivateKey());
174 assertNull(profile.getUserCert());
175 }
176
177 @Test
Benedict Wong8e3914c2020-04-09 21:49:05 -0700178 public void testBuildWithAllowedAlgorithmsAead() throws Exception {
179 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
180 builder.setAuthPsk(PSK_BYTES);
181
Yan Yan86783c32021-04-28 15:16:22 -0700182 List<String> allowedAlgorithms =
183 Arrays.asList(
184 IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
185 IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305);
Benedict Wong8e3914c2020-04-09 21:49:05 -0700186 builder.setAllowedAlgorithms(allowedAlgorithms);
187
188 final Ikev2VpnProfile profile = builder.build();
189 assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
190 }
191
192 @Test
193 public void testBuildWithAllowedAlgorithmsNormal() throws Exception {
194 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
195 builder.setAuthPsk(PSK_BYTES);
196
197 List<String> allowedAlgorithms =
Yan Yan86783c32021-04-28 15:16:22 -0700198 Arrays.asList(
199 IpSecAlgorithm.AUTH_HMAC_SHA512,
200 IpSecAlgorithm.AUTH_AES_XCBC,
201 IpSecAlgorithm.AUTH_AES_CMAC,
202 IpSecAlgorithm.CRYPT_AES_CBC,
203 IpSecAlgorithm.CRYPT_AES_CTR);
Benedict Wong8e3914c2020-04-09 21:49:05 -0700204 builder.setAllowedAlgorithms(allowedAlgorithms);
205
206 final Ikev2VpnProfile profile = builder.build();
207 assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
208 }
209
210 @Test
211 public void testSetAllowedAlgorithmsEmptyList() throws Exception {
212 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
213
214 try {
215 builder.setAllowedAlgorithms(new ArrayList<>());
216 fail("Expected exception due to no valid algorithm set");
217 } catch (IllegalArgumentException expected) {
218 }
219 }
220
221 @Test
222 public void testSetAllowedAlgorithmsInvalidList() throws Exception {
223 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
224 List<String> allowedAlgorithms = new ArrayList<>();
225
226 try {
227 builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA256));
228 fail("Expected exception due to missing encryption");
229 } catch (IllegalArgumentException expected) {
230 }
231
232 try {
233 builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.CRYPT_AES_CBC));
234 fail("Expected exception due to missing authentication");
235 } catch (IllegalArgumentException expected) {
236 }
237 }
238
239 @Test
240 public void testSetAllowedAlgorithmsInsecureAlgorithm() throws Exception {
241 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
242 List<String> allowedAlgorithms = new ArrayList<>();
243
244 try {
245 builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_MD5));
246 fail("Expected exception due to insecure algorithm");
247 } catch (IllegalArgumentException expected) {
248 }
249
250 try {
251 builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA1));
252 fail("Expected exception due to insecure algorithm");
253 } catch (IllegalArgumentException expected) {
254 }
255 }
256
257 @Test
Benedict Wong56420432019-11-01 16:45:08 -0700258 public void testBuildNoAuthMethodSet() throws Exception {
259 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
260
261 try {
262 builder.build();
263 fail("Expected exception due to lack of auth method");
264 } catch (IllegalArgumentException expected) {
265 }
266 }
267
Chiachang Wangb4a319b2022-01-06 16:55:41 +0800268
Chiachang Wang137bbed2022-02-11 15:32:30 +0800269 // TODO: Refer to Build.VERSION_CODES.SC_V2 when it's available in AOSP and mainline branch
270 @DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
Chiachang Wangb4a319b2022-01-06 16:55:41 +0800271 @Test
272 public void testBuildExcludeLocalRoutesSet() throws Exception {
273 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
274 builder.setAuthPsk(PSK_BYTES);
Chiachang Wangf8908742022-02-08 15:45:11 +0800275 builder.setLocalRoutesExcluded(true);
Chiachang Wangb4a319b2022-01-06 16:55:41 +0800276
277 final Ikev2VpnProfile profile = builder.build();
278 assertNotNull(profile);
Chiachang Wangf8908742022-02-08 15:45:11 +0800279 assertTrue(profile.areLocalRoutesExcluded());
Chiachang Wangb4a319b2022-01-06 16:55:41 +0800280
281 builder.setBypassable(false);
282 try {
283 builder.build();
284 fail("Expected exception because excludeLocalRoutes should be set only"
285 + " on the bypassable VPN");
286 } catch (IllegalArgumentException expected) {
287 }
288 }
289
Benedict Wong56420432019-11-01 16:45:08 -0700290 @Test
291 public void testBuildInvalidMtu() throws Exception {
292 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
293
294 try {
295 builder.setMaxMtu(500);
296 fail("Expected exception due to too-small MTU");
297 } catch (IllegalArgumentException expected) {
298 }
299 }
300
301 private void verifyVpnProfileCommon(VpnProfile profile) {
302 assertEquals(SERVER_ADDR_STRING, profile.server);
303 assertEquals(IDENTITY_STRING, profile.ipsecIdentifier);
304 assertEquals(mProxy, profile.proxy);
305 assertTrue(profile.isBypassable);
306 assertTrue(profile.isMetered);
307 assertEquals(TEST_MTU, profile.maxMtu);
308 }
309
310 @Test
311 public void testPskConvertToVpnProfile() throws Exception {
312 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
313
314 builder.setAuthPsk(PSK_BYTES);
315 final VpnProfile profile = builder.build().toVpnProfile();
316
317 verifyVpnProfileCommon(profile);
318 assertEquals(Ikev2VpnProfile.encodeForIpsecSecret(PSK_BYTES), profile.ipsecSecret);
319
320 // Check nothing else is set
321 assertEquals("", profile.username);
322 assertEquals("", profile.password);
323 assertEquals("", profile.ipsecUserCert);
324 assertEquals("", profile.ipsecCaCert);
325 }
326
327 @Test
328 public void testUsernamePasswordConvertToVpnProfile() throws Exception {
329 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
330
331 builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
332 final VpnProfile profile = builder.build().toVpnProfile();
333
334 verifyVpnProfileCommon(profile);
335 assertEquals(USERNAME_STRING, profile.username);
336 assertEquals(PASSWORD_STRING, profile.password);
337 assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
338
339 // Check nothing else is set
340 assertEquals("", profile.ipsecUserCert);
341 assertEquals("", profile.ipsecSecret);
342 }
343
344 @Test
345 public void testRsaConvertToVpnProfile() throws Exception {
346 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
347
348 builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
349 final VpnProfile profile = builder.build().toVpnProfile();
350
Benedict Wong94d31ad2020-01-17 19:41:38 -0800351 final String expectedSecret = Ikev2VpnProfile.PREFIX_INLINE
352 + Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded());
Benedict Wong56420432019-11-01 16:45:08 -0700353 verifyVpnProfileCommon(profile);
354 assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert);
355 assertEquals(
Benedict Wong94d31ad2020-01-17 19:41:38 -0800356 expectedSecret,
Benedict Wong56420432019-11-01 16:45:08 -0700357 profile.ipsecSecret);
358 assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
359
360 // Check nothing else is set
361 assertEquals("", profile.username);
362 assertEquals("", profile.password);
363 }
364
365 @Test
366 public void testPskFromVpnProfileDiscardsIrrelevantValues() throws Exception {
367 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
368
369 builder.setAuthPsk(PSK_BYTES);
370 final VpnProfile profile = builder.build().toVpnProfile();
371 profile.username = USERNAME_STRING;
372 profile.password = PASSWORD_STRING;
373 profile.ipsecCaCert = Ikev2VpnProfile.certificateToPemString(mServerRootCa);
374 profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
375
376 final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
377 assertNull(result.getUsername());
378 assertNull(result.getPassword());
379 assertNull(result.getUserCert());
380 assertNull(result.getRsaPrivateKey());
381 assertNull(result.getServerRootCaCert());
382 }
383
384 @Test
385 public void testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues() throws Exception {
386 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
387
388 builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
389 final VpnProfile profile = builder.build().toVpnProfile();
390 profile.ipsecSecret = new String(PSK_BYTES);
391 profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
392
393 final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
394 assertNull(result.getPresharedKey());
395 assertNull(result.getUserCert());
396 assertNull(result.getRsaPrivateKey());
397 }
398
399 @Test
400 public void testRsaFromVpnProfileDiscardsIrrelevantValues() throws Exception {
401 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
402
403 builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
404 final VpnProfile profile = builder.build().toVpnProfile();
405 profile.username = USERNAME_STRING;
406 profile.password = PASSWORD_STRING;
407
408 final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
409 assertNull(result.getUsername());
410 assertNull(result.getPassword());
411 assertNull(result.getPresharedKey());
412 }
413
414 @Test
415 public void testPskConversionIsLossless() throws Exception {
416 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
417
418 builder.setAuthPsk(PSK_BYTES);
419 final Ikev2VpnProfile ikeProfile = builder.build();
420
421 assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
422 }
423
424 @Test
425 public void testUsernamePasswordConversionIsLossless() throws Exception {
426 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
427
428 builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
429 final Ikev2VpnProfile ikeProfile = builder.build();
430
431 assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
432 }
433
434 @Test
435 public void testRsaConversionIsLossless() throws Exception {
436 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
437
438 builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
439 final Ikev2VpnProfile ikeProfile = builder.build();
440
441 assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
442 }
443
444 private static class CertificateAndKey {
445 public final X509Certificate cert;
446 public final PrivateKey key;
447
448 CertificateAndKey(X509Certificate cert, PrivateKey key) {
449 this.cert = cert;
450 this.key = key;
451 }
452 }
453
454 private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception {
455 final Date validityBeginDate =
456 new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L));
457 final Date validityEndDate =
458 new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L));
459
460 // Generate a keypair
461 final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
462 keyPairGenerator.initialize(512);
463 final KeyPair keyPair = keyPairGenerator.generateKeyPair();
464
465 final X500Principal dnName = new X500Principal("CN=test.android.com");
466 final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
467 certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
468 certGen.setSubjectDN(dnName);
469 certGen.setIssuerDN(dnName);
470 certGen.setNotBefore(validityBeginDate);
471 certGen.setNotAfter(validityEndDate);
472 certGen.setPublicKey(keyPair.getPublic());
473 certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
474
475 final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL");
476 return new CertificateAndKey(cert, keyPair.getPrivate());
477 }
478}