1 /* 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 17 package android.net; 18 19 import static org.junit.Assert.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 26 import android.os.Build; 27 import android.test.mock.MockContext; 28 29 import androidx.test.filters.SmallTest; 30 31 import com.android.internal.net.VpnProfile; 32 import com.android.internal.org.bouncycastle.x509.X509V1CertificateGenerator; 33 import com.android.net.module.util.ProxyUtils; 34 import com.android.testutils.DevSdkIgnoreRule; 35 import com.android.testutils.DevSdkIgnoreRunner; 36 37 import org.junit.Before; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 import java.math.BigInteger; 42 import java.security.KeyPair; 43 import java.security.KeyPairGenerator; 44 import java.security.PrivateKey; 45 import java.security.cert.X509Certificate; 46 import java.util.ArrayList; 47 import java.util.Arrays; 48 import java.util.Date; 49 import java.util.List; 50 import java.util.concurrent.TimeUnit; 51 52 import javax.security.auth.x500.X500Principal; 53 54 /** Unit tests for {@link Ikev2VpnProfile.Builder}. */ 55 @SmallTest 56 @RunWith(DevSdkIgnoreRunner.class) 57 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) 58 public 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 }; 74 private final ProxyInfo mProxy = ProxyInfo.buildDirectProxy( 75 SERVER_ADDR_STRING, -1, ProxyUtils.exclusionStringAsList(EXCL_LIST)); 76 77 private X509Certificate mUserCert; 78 private X509Certificate mServerRootCa; 79 private PrivateKey mPrivateKey; 80 81 @Before setUp()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 getBuilderWithDefaultOptions()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 testBuildValidProfileWithOptions()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()); 117 assertEquals(Ikev2VpnProfile.DEFAULT_ALGORITHMS, profile.getAllowedAlgorithms()); 118 } 119 120 @Test testBuildUsernamePasswordProfile()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 testBuildDigitalSignatureProfile()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 testBuildPresharedKeyProfile()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 testBuildWithAllowedAlgorithmsAead()172 public void testBuildWithAllowedAlgorithmsAead() throws Exception { 173 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 174 builder.setAuthPsk(PSK_BYTES); 175 176 List<String> allowedAlgorithms = 177 Arrays.asList( 178 IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 179 IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305); 180 builder.setAllowedAlgorithms(allowedAlgorithms); 181 182 final Ikev2VpnProfile profile = builder.build(); 183 assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms()); 184 } 185 186 @Test testBuildWithAllowedAlgorithmsNormal()187 public void testBuildWithAllowedAlgorithmsNormal() throws Exception { 188 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 189 builder.setAuthPsk(PSK_BYTES); 190 191 List<String> allowedAlgorithms = 192 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); 198 builder.setAllowedAlgorithms(allowedAlgorithms); 199 200 final Ikev2VpnProfile profile = builder.build(); 201 assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms()); 202 } 203 204 @Test testSetAllowedAlgorithmsEmptyList()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 testSetAllowedAlgorithmsInvalidList()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 testSetAllowedAlgorithmsInsecureAlgorithm()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 testBuildNoAuthMethodSet()252 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 262 @Test testBuildInvalidMtu()263 public void testBuildInvalidMtu() throws Exception { 264 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 265 266 try { 267 builder.setMaxMtu(500); 268 fail("Expected exception due to too-small MTU"); 269 } catch (IllegalArgumentException expected) { 270 } 271 } 272 verifyVpnProfileCommon(VpnProfile profile)273 private void verifyVpnProfileCommon(VpnProfile profile) { 274 assertEquals(SERVER_ADDR_STRING, profile.server); 275 assertEquals(IDENTITY_STRING, profile.ipsecIdentifier); 276 assertEquals(mProxy, profile.proxy); 277 assertTrue(profile.isBypassable); 278 assertTrue(profile.isMetered); 279 assertEquals(TEST_MTU, profile.maxMtu); 280 } 281 282 @Test testPskConvertToVpnProfile()283 public void testPskConvertToVpnProfile() throws Exception { 284 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 285 286 builder.setAuthPsk(PSK_BYTES); 287 final VpnProfile profile = builder.build().toVpnProfile(); 288 289 verifyVpnProfileCommon(profile); 290 assertEquals(Ikev2VpnProfile.encodeForIpsecSecret(PSK_BYTES), profile.ipsecSecret); 291 292 // Check nothing else is set 293 assertEquals("", profile.username); 294 assertEquals("", profile.password); 295 assertEquals("", profile.ipsecUserCert); 296 assertEquals("", profile.ipsecCaCert); 297 } 298 299 @Test testUsernamePasswordConvertToVpnProfile()300 public void testUsernamePasswordConvertToVpnProfile() throws Exception { 301 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 302 303 builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa); 304 final VpnProfile profile = builder.build().toVpnProfile(); 305 306 verifyVpnProfileCommon(profile); 307 assertEquals(USERNAME_STRING, profile.username); 308 assertEquals(PASSWORD_STRING, profile.password); 309 assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert); 310 311 // Check nothing else is set 312 assertEquals("", profile.ipsecUserCert); 313 assertEquals("", profile.ipsecSecret); 314 } 315 316 @Test testRsaConvertToVpnProfile()317 public void testRsaConvertToVpnProfile() throws Exception { 318 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 319 320 builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa); 321 final VpnProfile profile = builder.build().toVpnProfile(); 322 323 final String expectedSecret = Ikev2VpnProfile.PREFIX_INLINE 324 + Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded()); 325 verifyVpnProfileCommon(profile); 326 assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert); 327 assertEquals( 328 expectedSecret, 329 profile.ipsecSecret); 330 assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert); 331 332 // Check nothing else is set 333 assertEquals("", profile.username); 334 assertEquals("", profile.password); 335 } 336 337 @Test testPskFromVpnProfileDiscardsIrrelevantValues()338 public void testPskFromVpnProfileDiscardsIrrelevantValues() throws Exception { 339 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 340 341 builder.setAuthPsk(PSK_BYTES); 342 final VpnProfile profile = builder.build().toVpnProfile(); 343 profile.username = USERNAME_STRING; 344 profile.password = PASSWORD_STRING; 345 profile.ipsecCaCert = Ikev2VpnProfile.certificateToPemString(mServerRootCa); 346 profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert); 347 348 final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile); 349 assertNull(result.getUsername()); 350 assertNull(result.getPassword()); 351 assertNull(result.getUserCert()); 352 assertNull(result.getRsaPrivateKey()); 353 assertNull(result.getServerRootCaCert()); 354 } 355 356 @Test testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues()357 public void testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues() throws Exception { 358 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 359 360 builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa); 361 final VpnProfile profile = builder.build().toVpnProfile(); 362 profile.ipsecSecret = new String(PSK_BYTES); 363 profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert); 364 365 final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile); 366 assertNull(result.getPresharedKey()); 367 assertNull(result.getUserCert()); 368 assertNull(result.getRsaPrivateKey()); 369 } 370 371 @Test testRsaFromVpnProfileDiscardsIrrelevantValues()372 public void testRsaFromVpnProfileDiscardsIrrelevantValues() throws Exception { 373 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 374 375 builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa); 376 final VpnProfile profile = builder.build().toVpnProfile(); 377 profile.username = USERNAME_STRING; 378 profile.password = PASSWORD_STRING; 379 380 final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile); 381 assertNull(result.getUsername()); 382 assertNull(result.getPassword()); 383 assertNull(result.getPresharedKey()); 384 } 385 386 @Test testPskConversionIsLossless()387 public void testPskConversionIsLossless() throws Exception { 388 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 389 390 builder.setAuthPsk(PSK_BYTES); 391 final Ikev2VpnProfile ikeProfile = builder.build(); 392 393 assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile())); 394 } 395 396 @Test testUsernamePasswordConversionIsLossless()397 public void testUsernamePasswordConversionIsLossless() throws Exception { 398 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 399 400 builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa); 401 final Ikev2VpnProfile ikeProfile = builder.build(); 402 403 assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile())); 404 } 405 406 @Test testRsaConversionIsLossless()407 public void testRsaConversionIsLossless() throws Exception { 408 final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); 409 410 builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa); 411 final Ikev2VpnProfile ikeProfile = builder.build(); 412 413 assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile())); 414 } 415 416 private static class CertificateAndKey { 417 public final X509Certificate cert; 418 public final PrivateKey key; 419 CertificateAndKey(X509Certificate cert, PrivateKey key)420 CertificateAndKey(X509Certificate cert, PrivateKey key) { 421 this.cert = cert; 422 this.key = key; 423 } 424 } 425 generateRandomCertAndKeyPair()426 private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception { 427 final Date validityBeginDate = 428 new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L)); 429 final Date validityEndDate = 430 new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L)); 431 432 // Generate a keypair 433 final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 434 keyPairGenerator.initialize(512); 435 final KeyPair keyPair = keyPairGenerator.generateKeyPair(); 436 437 final X500Principal dnName = new X500Principal("CN=test.android.com"); 438 final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator(); 439 certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis())); 440 certGen.setSubjectDN(dnName); 441 certGen.setIssuerDN(dnName); 442 certGen.setNotBefore(validityBeginDate); 443 certGen.setNotAfter(validityEndDate); 444 certGen.setPublicKey(keyPair.getPublic()); 445 certGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); 446 447 final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL"); 448 return new CertificateAndKey(cert, keyPair.getPrivate()); 449 } 450 } 451