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