1 /* 2 * Copyright (C) 2021 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.vcn.persistablebundleutils; 18 19 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_AUTOMATIC_KEEPALIVE_ON_OFF; 20 import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION; 21 import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES; 22 import static android.system.OsConstants.AF_INET; 23 import static android.system.OsConstants.AF_INET6; 24 import static android.telephony.TelephonyManager.APPTYPE_USIM; 25 26 import static org.junit.Assert.assertEquals; 27 28 import android.net.InetAddresses; 29 import android.net.eap.EapSessionConfig; 30 import android.net.ipsec.ike.IkeFqdnIdentification; 31 import android.net.ipsec.ike.IkeSessionParams; 32 import android.os.PersistableBundle; 33 34 import androidx.test.InstrumentationRegistry; 35 import androidx.test.filters.SmallTest; 36 import androidx.test.runner.AndroidJUnit4; 37 38 import com.android.internal.org.bouncycastle.util.io.pem.PemObject; 39 import com.android.internal.org.bouncycastle.util.io.pem.PemReader; 40 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 44 import java.io.InputStream; 45 import java.io.InputStreamReader; 46 import java.net.Inet4Address; 47 import java.net.Inet6Address; 48 import java.net.InetAddress; 49 import java.nio.charset.StandardCharsets; 50 import java.security.cert.CertificateFactory; 51 import java.security.cert.X509Certificate; 52 import java.security.interfaces.RSAPrivateKey; 53 import java.util.concurrent.TimeUnit; 54 55 @RunWith(AndroidJUnit4.class) 56 @SmallTest 57 public class IkeSessionParamsUtilsTest { 58 // Public for use in VcnGatewayConnectionConfigTest, EncryptedTunnelParamsUtilsTest createBuilderMinimum()59 public static IkeSessionParams.Builder createBuilderMinimum() { 60 final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100"); 61 62 // TODO: b/185941731 Make sure all valid IKE_OPTIONS are added and validated. 63 return new IkeSessionParams.Builder() 64 .setServerHostname(serverAddress.getHostAddress()) 65 .addSaProposal(SaProposalUtilsTest.buildTestIkeSaProposal()) 66 .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net")) 67 .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net")) 68 .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) 69 .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) 70 .setAuthPsk("psk".getBytes()); 71 } 72 verifyPersistableBundleEncodeDecodeIsLossless(IkeSessionParams params)73 private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeSessionParams params) { 74 final PersistableBundle bundle = IkeSessionParamsUtils.toPersistableBundle(params); 75 final IkeSessionParams result = IkeSessionParamsUtils.fromPersistableBundle(bundle); 76 77 assertEquals(result, params); 78 } 79 80 @Test testEncodeRecodeParamsWithLifetimes()81 public void testEncodeRecodeParamsWithLifetimes() throws Exception { 82 final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(20L); 83 final int softLifetime = (int) TimeUnit.HOURS.toSeconds(10L); 84 final IkeSessionParams params = 85 createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); 86 verifyPersistableBundleEncodeDecodeIsLossless(params); 87 } 88 89 @Test testEncodeRecodeParamsWithDpdDelay()90 public void testEncodeRecodeParamsWithDpdDelay() throws Exception { 91 final int dpdDelay = (int) TimeUnit.MINUTES.toSeconds(10L); 92 final IkeSessionParams params = createBuilderMinimum().setDpdDelaySeconds(dpdDelay).build(); 93 94 verifyPersistableBundleEncodeDecodeIsLossless(params); 95 } 96 97 @Test testEncodeRecodeParamsWithNattKeepalive()98 public void testEncodeRecodeParamsWithNattKeepalive() throws Exception { 99 final int nattKeepAliveDelay = (int) TimeUnit.MINUTES.toSeconds(5L); 100 final IkeSessionParams params = 101 createBuilderMinimum().setNattKeepAliveDelaySeconds(nattKeepAliveDelay).build(); 102 103 verifyPersistableBundleEncodeDecodeIsLossless(params); 104 } 105 106 @Test testEncodeRecodeParamsWithRetransmissionTimeouts()107 public void testEncodeRecodeParamsWithRetransmissionTimeouts() throws Exception { 108 final int[] retransmissionTimeout = new int[] {500, 500, 500, 500, 500, 500}; 109 final IkeSessionParams params = 110 createBuilderMinimum() 111 .setRetransmissionTimeoutsMillis(retransmissionTimeout) 112 .build(); 113 114 verifyPersistableBundleEncodeDecodeIsLossless(params); 115 } 116 117 @Test testEncodeRecodeParamsWithConfigRequests()118 public void testEncodeRecodeParamsWithConfigRequests() throws Exception { 119 final Inet4Address ipv4Address = 120 (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100"); 121 final Inet6Address ipv6Address = 122 (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1"); 123 124 final IkeSessionParams params = 125 createBuilderMinimum() 126 .addPcscfServerRequest(AF_INET) 127 .addPcscfServerRequest(AF_INET6) 128 .addPcscfServerRequest(ipv4Address) 129 .addPcscfServerRequest(ipv6Address) 130 .build(); 131 verifyPersistableBundleEncodeDecodeIsLossless(params); 132 } 133 134 @Test testEncodeRecodeParamsWithAuthPsk()135 public void testEncodeRecodeParamsWithAuthPsk() throws Exception { 136 final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build(); 137 verifyPersistableBundleEncodeDecodeIsLossless(params); 138 } 139 createBuilderMinimumWithEap()140 private static IkeSessionParams.Builder createBuilderMinimumWithEap() throws Exception { 141 final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); 142 143 final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII); 144 final int subId = 1; 145 final EapSessionConfig eapConfig = 146 new EapSessionConfig.Builder() 147 .setEapIdentity(eapId) 148 .setEapSimConfig(subId, APPTYPE_USIM) 149 .setEapAkaConfig(subId, APPTYPE_USIM) 150 .build(); 151 return createBuilderMinimum().setAuthEap(serverCaCert, eapConfig); 152 } 153 154 @Test testEncodeDecodeParamsWithIkeOptions()155 public void testEncodeDecodeParamsWithIkeOptions() throws Exception { 156 final IkeSessionParams.Builder builder = 157 createBuilderMinimumWithEap() 158 .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) 159 .addIkeOption(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH) 160 .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) 161 .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) 162 .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) 163 .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY) 164 .addIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION) 165 .addIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES) 166 .addIkeOption(IKE_OPTION_AUTOMATIC_KEEPALIVE_ON_OFF); 167 168 verifyPersistableBundleEncodeDecodeIsLossless(builder.build()); 169 } 170 openAssetsFile(String fileName)171 private static InputStream openAssetsFile(String fileName) throws Exception { 172 return InstrumentationRegistry.getContext().getResources().getAssets().open(fileName); 173 } 174 createCertFromPemFile(String fileName)175 private static X509Certificate createCertFromPemFile(String fileName) throws Exception { 176 final CertificateFactory factory = CertificateFactory.getInstance("X.509"); 177 return (X509Certificate) factory.generateCertificate(openAssetsFile(fileName)); 178 } 179 createRsaPrivateKeyFromKeyFile(String fileName)180 private static RSAPrivateKey createRsaPrivateKeyFromKeyFile(String fileName) throws Exception { 181 final PemObject pemObject = 182 new PemReader(new InputStreamReader(openAssetsFile(fileName))).readPemObject(); 183 return (RSAPrivateKey) CertUtils.privateKeyFromByteArray(pemObject.getContent()); 184 } 185 186 @Test testEncodeRecodeParamsWithDigitalSignAuth()187 public void testEncodeRecodeParamsWithDigitalSignAuth() throws Exception { 188 final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem"); 189 final X509Certificate clientEndCert = createCertFromPemFile("client-end-cert.pem"); 190 final RSAPrivateKey clientPrivateKey = 191 createRsaPrivateKeyFromKeyFile("client-private-key.key"); 192 193 final IkeSessionParams params = 194 createBuilderMinimum() 195 .setAuthDigitalSignature(serverCaCert, clientEndCert, clientPrivateKey) 196 .build(); 197 verifyPersistableBundleEncodeDecodeIsLossless(params); 198 } 199 200 @Test testEncodeRecodeParamsWithEapAuth()201 public void testEncodeRecodeParamsWithEapAuth() throws Exception { 202 final IkeSessionParams params = createBuilderMinimumWithEap().build(); 203 verifyPersistableBundleEncodeDecodeIsLossless(params); 204 } 205 } 206