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