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