Merge "Migrate IPsec CTS out of tests/tests/net" am: d8f0f4a3c7 am: 7ccfde6046 am: c4c5a231f4

Original change: https://android-review.googlesource.com/c/platform/cts/+/1455144

Change-Id: I5f280c499c61c6d08c0b3f74559951541104d10d
This commit is contained in:
Yan Yan
2020-10-15 18:19:07 +00:00
committed by Automerger Merge Worker
24 changed files with 0 additions and 4311 deletions

View File

@@ -1,48 +0,0 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
android_test {
name: "CtsIkeTestCases",
defaults: ["cts_defaults"],
// Include both the 32 and 64 bit versions
compile_multilib: "both",
libs: [
"android.net.ipsec.ike.stubs.system",
"android.test.base",
],
srcs: [
"src/**/*.java",
":ike-test-utils",
],
static_libs: [
"androidx.test.ext.junit",
"compatibility-device-util-axt",
"ctstestrunner-axt",
"net-tests-utils",
],
platform_apis: true,
// Tag this module as a cts test artifact
test_suites: [
"cts",
"mts",
"vts",
"general-tests",
],
}

View File

@@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.net.ipsec.cts"
android:targetSandboxVersion="2">
<!--Allow tests to call ConnectivityManager#getActiveNetwork()-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--Allow tests to create socket -->
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="CtsIkeTestCases">
<uses-library android:name="android.test.runner" />
<uses-library android:name="android.net.ipsec.ike" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.net.ipsec.cts"
android:label="CTS tests of android.net.ipsec">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
</instrumentation>
</manifest>

View File

@@ -1,33 +0,0 @@
<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="Config for CTS IKE test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="networking" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsIkeTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.net.ipsec.cts" />
<option name="hidden-api-checks" value="false" />
</test>
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
<option name="mainline-module-package-name" value="com.google.android.ipsec" />
</object>
</configuration>

View File

@@ -1,3 +0,0 @@
lorenzo@google.com
nharold@google.com
satk@google.com

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL
8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu
7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K
Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i
pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS
jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK
a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub
G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n
zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo
zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL
gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc
9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf
spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL
ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms
TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy
GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK
QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ
+K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE
i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh
fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU
ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+
NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN
mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR
wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G
xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf
idNFcaIrC52PtZIH7QCzdDY=
-----END PRIVATE KEY-----

View File

@@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu
ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG
A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0
LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE
CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc
6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw
D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC
25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG
R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL
bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu
bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK
I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio
4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP
ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab
SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7
T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy
rmkYV2MAWguFeckh
-----END CERTIFICATE-----

View File

@@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDaDCCAlCgAwIBAgIIIbjMyRn2770wDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE
BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h
bmRyb2lkLm5ldDAeFw0xOTA5MzAxODQzMThaFw0yNDA5MjgxODQzMThaMEExCzAJ
BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSAwHgYDVQQDExdvbmUuY2EudGVz
dC5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNN
sRr5Z30rAEw2jrAh/BIekbEy/MvOucAr1w0lxH71p+ybRBx5Bj7G07UGXbL659gm
meMV6nabY4HjQXNMq22POiJBZj+U+rw34br6waljBttxCmmJac1VvgqNsSspXjRy
NbiVQdFjyKSX0NOPcEkwANk15mZbOgJBaYYc8jQCY2G/p8eARVBTLJCy8LEwEU6j
XRv/4eYST79qpBFc7gQQj2FLmh9oppDIvcIVBHwtd1tBoVuehRSud1o8vQRkl/HJ
Mrwp24nO5YYhmVNSFRtBpmWMSu1KknFUwkOebINUNsKXXHebVa7cP4XIQUL8mRT3
5X9rFJFSQJE01S3NjNMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
Af8EBAMCAQYwHQYDVR0OBBYEFHK3FIm7g8dxEIwK9zMAO8EWhRYxMB8GA1UdIwQY
MBaAFEmfqEeF14Nj91ekIpR+sVhCEoAaMA0GCSqGSIb3DQEBCwUAA4IBAQAeMlXT
TnxZo8oz0204gKZ63RzlgDpJ7SqA3qFG+pV+TiqGfSuVkXuIdOskjxJnA9VxUzrr
LdMTCn5e0FK6wCYjZ2GT/CD7oD3vSMkzGbLGNcNJhhDHUq8BOLPkPzz/rwQFPBSb
zr6hsiVXphEt/psGoN7Eu9blPeQaIwMfWnaufAwF664S/3dmCRbNMWSam1qzzz8q
jr0cDOIMa//ZIAcM16cvoBK6pFGnUmuoJYYRtfpY5MmfCWz0sCJxENIX/lxyhd7N
FdRALA1ZP3E//Tn2vQoeFjbKaAba527RE26HgHJ9zZDo1nn8J8J/YwYRJdBWM/3S
LYebNiMtcyB5nIkj
-----END CERTIFICATE-----

View File

@@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDZzCCAk+gAwIBAgIIKWCREnNCs+wwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF29uZS5jYS50ZXN0LmFu
ZHJvaWQubmV0MB4XDTE5MDkzMDE4NDQwMloXDTI0MDkyODE4NDQwMlowQTELMAkG
A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0
LmFuZHJvaWQubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLUa
RqkYl2m7lUmMnkooqO0DNNY1aN9r7mJc3ndYn5gjkpb3yLgOYPDNLcQerV6uWk/u
qKudNHed2dInGonl3oxwwv7++6oUvvtrSWLDZlRg16GsdIE1Y98DSMQWkSxevYy9
Nh6FGTdlBFQVMpiMa8qHEkrOyKsy85yCW1sgzlpGTIBwbDAqYtwe3rgbwyHwUtfy
0EU++DBcR4ll/pDqB0OQtW5E3AOq2GH1iaGeFLKSUQ5KAbdI8y4/b8IkSDffvxcc
kXig7S54aLrNlL/ZjQ+H4Chgjj2A5wMucd81+Fb60Udej73ICL9PpMPnXQ1+BVYd
MJ/txjLNmrOJG9yEHQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
/wQEAwIBBjAdBgNVHQ4EFgQUcqSu1uRYT/DLbLoDNUz38nGvCKQwHwYDVR0jBBgw
FoAUcrcUibuDx3EQjAr3MwA7wRaFFjEwDQYJKoZIhvcNAQELBQADggEBADY461GT
Rw0dGnD07xaGJcI0i0pV+WnGSrl1s1PAIdMYihJAqYnh10fXbFXLm2WMWVmv/pxs
FI/xDJno+pd4mCa/sIhm63ar/Nv+lFQmcpIlvSlKnhhV4SLNBeqbVhPBGTCHfrG4
aIyCwm1KJsnkWbf03crhSskR/2CXIjX6lcAy7K3fE2u1ELpAdH0kMJR7VXkLFLUm
gqe9YCluR0weMpe2sCaOGzdVzQSmMMCzGP5cxeFR5U6K40kMOpiW11JNmQ06xI/m
YVkMNwoiV/ITT0/C/g9FxJmkO0mVSLEqxaLS/hNiQNDlroVM0rbxhzviXLI3R3AO
50VvlOQYGxWed/I=
-----END CERTIFICATE-----

View File

@@ -1,20 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDSDCCAjCgAwIBAgIITJQJ6HC1rjwwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE
BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h
bmRyb2lkLm5ldDAeFw0xOTA5MzAxNzU1NTJaFw0yOTA5MjcxNzU1NTJaMEIxCzAJ
BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSEwHwYDVQQDExhyb290LmNhLnRl
c3QuYW5kcm9pZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCT
q3hGF+JvLaB1xW7KGKmaxiQ7BxX2Sn7cbp7ggoVYXsFlBUuPPv3+Vg5PfPCPhsJ8
/7w4HyKo3uc/vHs5HpQ7rSd9blhAkfmJci2ULLq73FB8Mix4CzPwMx29RrN1X9bU
z4G0vJMczIBGxbZ0uw7n8bKcXBV7AIeax+J8lseEZ3k8iSuBkUJqGIpPFKTqByFZ
A1Lvt47xkON5SZh6c/Oe+o6291wXaCOJUSAKv6PAWZkq9HeD2fqKA/ck9dBaz1M3
YvzQ9V/7so3/dECjAfKia388h1I6XSGNUM+d5hpxMXpAFgG42eUXHpJ10OjDvSwd
7ZSC91/kRQewUomEKBK1AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgEGMB0GA1UdDgQWBBRJn6hHhdeDY/dXpCKUfrFYQhKAGjANBgkqhkiG
9w0BAQsFAAOCAQEAig/94aGfHBhZuvbbhwAK4rUNpizmR567u0ZJ+QUEKyAlo9lT
ZWYHSm7qTAZYvPEjzTQIptnAlxCHePXh3Cfwgo+r82lhG2rcdI03iRyvHWjM8gyk
BXCJTi0Q08JHHpTP6GnAqpz58qEIFkk8P766zNXdhYrGPOydF+p7MFcb1Zv1gum3
zmRLt0XUAMfjPUv1Bl8kTKFxH5lkMBLR1E0jnoJoTTfgRPrf9CuFSoh48n7YhoBT
KV75xZY8b8+SuB0v6BvQmkpKZGoxBjuVsShyG7q1+4JTAtwhiP7BlkDvVkaBEi7t
WIMFp2r2ZDisHgastNaeYFyzHYz9g1FCCrHQ4w==
-----END CERTIFICATE-----

View File

@@ -1,98 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.eap.cts;
import static android.telephony.TelephonyManager.APPTYPE_USIM;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.net.eap.EapSessionConfig;
import android.net.eap.EapSessionConfig.EapAkaConfig;
import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
import android.net.eap.EapSessionConfig.EapMsChapV2Config;
import android.net.eap.EapSessionConfig.EapSimConfig;
import android.net.eap.EapSessionConfig.EapUiccConfig;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class EapSessionConfigTest {
// These constants are IANA-defined values and are copies of hidden constants in
// frameworks/opt/net/ike/src/java/com/android/internal/net/eap/message/EapData.java.
private static final int EAP_TYPE_SIM = 18;
private static final int EAP_TYPE_AKA = 23;
private static final int EAP_TYPE_MSCHAP_V2 = 26;
private static final int EAP_TYPE_AKA_PRIME = 50;
private static final int SUB_ID = 1;
private static final byte[] EAP_IDENTITY = "test@android.net".getBytes();
private static final String NETWORK_NAME = "android.net";
private static final String EAP_MSCHAPV2_USERNAME = "username";
private static final String EAP_MSCHAPV2_PASSWORD = "password";
@Test
public void testBuildWithAllEapMethods() {
EapSessionConfig result =
new EapSessionConfig.Builder()
.setEapIdentity(EAP_IDENTITY)
.setEapSimConfig(SUB_ID, APPTYPE_USIM)
.setEapAkaConfig(SUB_ID, APPTYPE_USIM)
.setEapAkaPrimeConfig(
SUB_ID,
APPTYPE_USIM,
NETWORK_NAME,
true /* allowMismatchedNetworkNames */)
.setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD)
.build();
assertArrayEquals(EAP_IDENTITY, result.getEapIdentity());
EapSimConfig eapSimConfig = result.getEapSimConfig();
assertNotNull(eapSimConfig);
assertEquals(EAP_TYPE_SIM, eapSimConfig.getMethodType());
verifyEapUiccConfigCommon(eapSimConfig);
EapAkaConfig eapAkaConfig = result.getEapAkaConfig();
assertNotNull(eapAkaConfig);
assertEquals(EAP_TYPE_AKA, eapAkaConfig.getMethodType());
verifyEapUiccConfigCommon(eapAkaConfig);
EapAkaPrimeConfig eapAkaPrimeConfig = result.getEapAkaPrimeConfig();
assertNotNull(eapAkaPrimeConfig);
assertEquals(EAP_TYPE_AKA_PRIME, eapAkaPrimeConfig.getMethodType());
assertEquals(NETWORK_NAME, eapAkaPrimeConfig.getNetworkName());
assertTrue(NETWORK_NAME, eapAkaPrimeConfig.allowsMismatchedNetworkNames());
verifyEapUiccConfigCommon(eapAkaPrimeConfig);
EapMsChapV2Config eapMsChapV2Config = result.getEapMsChapV2onfig();
assertNotNull(eapMsChapV2Config);
assertEquals(EAP_TYPE_MSCHAP_V2, eapMsChapV2Config.getMethodType());
assertEquals(EAP_MSCHAPV2_USERNAME, eapMsChapV2Config.getUsername());
assertEquals(EAP_MSCHAPV2_PASSWORD, eapMsChapV2Config.getPassword());
}
private void verifyEapUiccConfigCommon(EapUiccConfig config) {
assertEquals(SUB_ID, config.getSubId());
assertEquals(APPTYPE_USIM, config.getAppType());
}
}

View File

@@ -1,230 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.net.LinkAddress;
import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.ChildSessionParams;
import android.net.ipsec.ike.TransportModeChildSessionParams;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address;
import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer;
import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer;
import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask;
import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address;
import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer;
import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.Inet4Address;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class ChildSessionParamsTest extends IkeTestBase {
private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(3L);
private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(1L);
// Random proposal. Content doesn't matter
private final ChildSaProposal mSaProposal =
SaProposalTest.buildChildSaProposalWithCombinedModeCipher();
private void verifyTunnelModeChildParamsWithDefaultValues(ChildSessionParams childParams) {
assertTrue(childParams instanceof TunnelModeChildSessionParams);
verifyChildParamsWithDefaultValues(childParams);
}
private void verifyTunnelModeChildParamsWithCustomizedValues(ChildSessionParams childParams) {
assertTrue(childParams instanceof TunnelModeChildSessionParams);
verifyChildParamsWithCustomizedValues(childParams);
}
private void verifyTransportModeChildParamsWithDefaultValues(ChildSessionParams childParams) {
assertTrue(childParams instanceof TransportModeChildSessionParams);
verifyChildParamsWithDefaultValues(childParams);
}
private void verifyTransportModeChildParamsWithCustomizedValues(
ChildSessionParams childParams) {
assertTrue(childParams instanceof TransportModeChildSessionParams);
verifyChildParamsWithCustomizedValues(childParams);
}
private void verifyChildParamsWithDefaultValues(ChildSessionParams childParams) {
assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals());
// Do not do assertEquals to the default values to be avoid being a change-detector test
assertTrue(childParams.getHardLifetimeSeconds() > childParams.getSoftLifetimeSeconds());
assertTrue(childParams.getSoftLifetimeSeconds() > 0);
assertEquals(
Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS),
childParams.getInboundTrafficSelectors());
assertEquals(
Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS),
childParams.getOutboundTrafficSelectors());
}
private void verifyChildParamsWithCustomizedValues(ChildSessionParams childParams) {
assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals());
assertEquals(HARD_LIFETIME_SECONDS, childParams.getHardLifetimeSeconds());
assertEquals(SOFT_LIFETIME_SECONDS, childParams.getSoftLifetimeSeconds());
assertEquals(
Arrays.asList(INBOUND_V4_TS, INBOUND_V6_TS),
childParams.getInboundTrafficSelectors());
assertEquals(
Arrays.asList(OUTBOUND_V4_TS, OUTBOUND_V6_TS),
childParams.getOutboundTrafficSelectors());
}
@Test
public void testBuildTransportModeParamsWithDefaultValues() {
TransportModeChildSessionParams childParams =
new TransportModeChildSessionParams.Builder().addSaProposal(mSaProposal).build();
verifyTransportModeChildParamsWithDefaultValues(childParams);
}
@Test
public void testBuildTunnelModeParamsWithDefaultValues() {
TunnelModeChildSessionParams childParams =
new TunnelModeChildSessionParams.Builder().addSaProposal(mSaProposal).build();
verifyTunnelModeChildParamsWithDefaultValues(childParams);
assertTrue(childParams.getConfigurationRequests().isEmpty());
}
@Test
public void testBuildTransportModeParamsWithCustomizedValues() {
TransportModeChildSessionParams childParams =
new TransportModeChildSessionParams.Builder()
.addSaProposal(mSaProposal)
.setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS)
.addInboundTrafficSelectors(INBOUND_V4_TS)
.addInboundTrafficSelectors(INBOUND_V6_TS)
.addOutboundTrafficSelectors(OUTBOUND_V4_TS)
.addOutboundTrafficSelectors(OUTBOUND_V6_TS)
.build();
verifyTransportModeChildParamsWithCustomizedValues(childParams);
}
@Test
public void testBuildTunnelModeParamsWithCustomizedValues() {
TunnelModeChildSessionParams childParams =
new TunnelModeChildSessionParams.Builder()
.addSaProposal(mSaProposal)
.setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS)
.addInboundTrafficSelectors(INBOUND_V4_TS)
.addInboundTrafficSelectors(INBOUND_V6_TS)
.addOutboundTrafficSelectors(OUTBOUND_V4_TS)
.addOutboundTrafficSelectors(OUTBOUND_V6_TS)
.build();
verifyTunnelModeChildParamsWithCustomizedValues(childParams);
}
@Test
public void testBuildChildSessionParamsWithConfigReq() {
TunnelModeChildSessionParams childParams =
new TunnelModeChildSessionParams.Builder()
.addSaProposal(mSaProposal)
.addInternalAddressRequest(AF_INET)
.addInternalAddressRequest(AF_INET6)
.addInternalAddressRequest(AF_INET6)
.addInternalAddressRequest(IPV4_ADDRESS_REMOTE)
.addInternalAddressRequest(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN)
.addInternalDnsServerRequest(AF_INET)
.addInternalDnsServerRequest(AF_INET6)
.addInternalDhcpServerRequest(AF_INET)
.addInternalDhcpServerRequest(AF_INET)
.build();
verifyTunnelModeChildParamsWithDefaultValues(childParams);
// Verify config request types and number of requests for each type
Map<Class<? extends TunnelModeChildConfigRequest>, Integer> expectedAttributeCounts =
new HashMap<>();
expectedAttributeCounts.put(ConfigRequestIpv4Address.class, 2);
expectedAttributeCounts.put(ConfigRequestIpv6Address.class, 3);
expectedAttributeCounts.put(ConfigRequestIpv4Netmask.class, 1);
expectedAttributeCounts.put(ConfigRequestIpv4DnsServer.class, 1);
expectedAttributeCounts.put(ConfigRequestIpv6DnsServer.class, 1);
expectedAttributeCounts.put(ConfigRequestIpv4DhcpServer.class, 2);
verifyConfigRequestTypes(expectedAttributeCounts, childParams.getConfigurationRequests());
// Verify specific IPv4 address request
Set<Inet4Address> expectedV4Addresses = new HashSet<>();
expectedV4Addresses.add(IPV4_ADDRESS_REMOTE);
verifySpecificV4AddrConfigReq(expectedV4Addresses, childParams);
// Verify specific IPv6 address request
Set<LinkAddress> expectedV6Addresses = new HashSet<>();
expectedV6Addresses.add(new LinkAddress(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN));
verifySpecificV6AddrConfigReq(expectedV6Addresses, childParams);
}
protected void verifySpecificV4AddrConfigReq(
Set<Inet4Address> expectedAddresses, TunnelModeChildSessionParams childParams) {
for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) {
if (req instanceof ConfigRequestIpv4Address
&& ((ConfigRequestIpv4Address) req).getAddress() != null) {
Inet4Address address = ((ConfigRequestIpv4Address) req).getAddress();
// Fail if expectedAddresses does not contain this address
assertTrue(expectedAddresses.remove(address));
}
}
// Fail if any expected address is not found in result
assertTrue(expectedAddresses.isEmpty());
}
protected void verifySpecificV6AddrConfigReq(
Set<LinkAddress> expectedAddresses, TunnelModeChildSessionParams childParams) {
for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) {
if (req instanceof ConfigRequestIpv6Address
&& ((ConfigRequestIpv6Address) req).getAddress() != null) {
ConfigRequestIpv6Address ipv6AddrReq = (ConfigRequestIpv6Address) req;
// Fail if expectedAddresses does not contain this address
LinkAddress address =
new LinkAddress(ipv6AddrReq.getAddress(), ipv6AddrReq.getPrefixLength());
assertTrue(expectedAddresses.remove(address));
}
}
// Fail if any expected address is not found in result
assertTrue(expectedAddresses.isEmpty());
}
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeIpv4AddrIdentification;
import android.net.ipsec.ike.IkeIpv6AddrIdentification;
import android.net.ipsec.ike.IkeKeyIdIdentification;
import android.net.ipsec.ike.IkeRfc822AddrIdentification;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import javax.security.auth.x500.X500Principal;
@RunWith(AndroidJUnit4.class)
public final class IkeIdentificationTest extends IkeTestBase {
@Test
public void testIkeDerAsn1DnIdentification() throws Exception {
X500Principal asn1Dn = new X500Principal(LOCAL_ASN1_DN_STRING);
IkeDerAsn1DnIdentification ikeId = new IkeDerAsn1DnIdentification(asn1Dn);
assertEquals(asn1Dn, ikeId.derAsn1Dn);
}
@Test
public void testIkeFqdnIdentification() throws Exception {
IkeFqdnIdentification ikeId = new IkeFqdnIdentification(LOCAL_HOSTNAME);
assertEquals(LOCAL_HOSTNAME, ikeId.fqdn);
}
@Test
public void testIkeIpv4AddrIdentification() throws Exception {
IkeIpv4AddrIdentification ikeId = new IkeIpv4AddrIdentification(IPV4_ADDRESS_LOCAL);
assertEquals(IPV4_ADDRESS_LOCAL, ikeId.ipv4Address);
}
@Test
public void testIkeIpv6AddrIdentification() throws Exception {
IkeIpv6AddrIdentification ikeId = new IkeIpv6AddrIdentification(IPV6_ADDRESS_LOCAL);
assertEquals(IPV6_ADDRESS_LOCAL, ikeId.ipv6Address);
}
@Test
public void testIkeKeyIdIdentification() throws Exception {
IkeKeyIdIdentification ikeId = new IkeKeyIdIdentification(LOCAL_KEY_ID);
assertArrayEquals(LOCAL_KEY_ID, ikeId.keyId);
}
@Test
public void testIkeRfc822AddrIdentification() throws Exception {
IkeRfc822AddrIdentification ikeId = new IkeRfc822AddrIdentification(LOCAL_RFC822_NAME);
assertEquals(LOCAL_RFC822_NAME, ikeId.rfc822Name);
}
}

View File

@@ -1,211 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import android.net.InetAddresses;
import android.net.LinkAddress;
import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTrafficSelector;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.net.ipsec.ike.testutils.CertUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList;
import java.util.Arrays;
import javax.security.auth.x500.X500Principal;
/**
* Explicitly test setting up transport mode Child SA so that devices do not have
* FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in
* IkeSessionPskTest and authentication method is orthogonal to Child mode.
*/
@RunWith(AndroidJUnit4.class)
public class IkeSessionDigitalSignatureTest extends IkeSessionTestBase {
private static final int EXPECTED_AUTH_REQ_FRAG_COUNT = 3;
private static final String IKE_INIT_RESP =
"46B8ECA1E0D72A18BF3FA1C2CB1EE86F21202220000000000000015022000030"
+ "0000002C010100040300000C0100000C800E0100030000080300000503000008"
+ "0200000400000008040000022800008800020000328451C8A976CE69E407966A"
+ "50D7320C4197A15A07267CE1B16BAFF9BDBBDEC1FDCDAAF7175ADF9AA8DB55DB"
+ "2D70C012D01D914C4EDEF6E8B226868EA1D01B2ED0C4C5C86E6BFE566010EC0C"
+ "33BA1C93666430B88BDA0470D82CC4F4416F49E3E361E3017C9F27811A66718B"
+ "389E1800915D776D59AA528A7E1D1B7815D35144290000249FE8FABE7F43D917"
+ "CE370DE2FD9C22BBC082951AC26C1BA26DE795470F2C25BC2900001C00004004"
+ "AE388EC86D6D1A470D44142D01AB2E85A7AC14182900001C0000400544A235A4"
+ "171C884286B170F48FFC181DB428D87D290000080000402E290000100000402F"
+ "00020003000400050000000800004014";
private static final String IKE_AUTH_RESP_FRAG_1 =
"46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000004E0240004C4"
+ "00010002DF6750A2D1D5675006F9F6230BB886FFD20CFB973FD04963CFD7A528"
+ "560598C58CC44178B2FCBBBBB271387AC81A664B7E7F1055B912F8C686E287C9"
+ "D31684C66339151AB86DA3CF1DA664052FA97687634558A1E9E6B37E16A86BD1"
+ "68D76DA5E2E1E0B7E98EB662D80D542307015D2BF134EBBBE425D6954FE8C2C4"
+ "D31D16C16AA0521C3C481F873ECF25BB8B05AC6083775C1821CAAB1E35A3955D"
+ "85ACC599574142E1DD5B262D6E5365CBF6EBE92FFCC16BC29EC3239456F3B202"
+ "492551C0F6D752ADCCA56D506D50CC8809EF6BC56EAD005586F7168F76445FD3"
+ "1366CC62D32C0C19B28210B8F813F97CD6A447C3857EFD6EC483DDA8ACD9870E"
+ "5A21B9C66F0FA44496C0C3D05E8859A1A4CFC88155D0C411BABC13033DD41FA4"
+ "AF08CE7734A146687F374F95634D1F26843203CA1FFD05CA3EB150CEA02FBF14"
+ "712B7A1C9BC7616A086E7FCA059E7D64EFF98DB895B32F8F7002762AF7D12F23"
+ "31E9DD25174C4CE273E5392BBB48F50B7A3E0187181216265F6A4FC7B91BE0AB"
+ "C601A580149D4B07411AE99DDB1944B977E86ADC9746605C60A92B569EEFAFFC"
+ "3A888D187B75D8F13249689FC28EBCD62B5E03AF171F3A561F0DEA3B1A75F531"
+ "971157DCE1E7BC6E7789FF3E8156015BC9C521EFE48996B41471D33BF09864E4"
+ "2436E8D7EB6218CDE7716DA754A924B123A63E25585BF27F4AC043A0C4AECE38"
+ "BB59DD62F5C0EC657206A76CED1BD26262237DA1CA6815435992A825758DEBEC"
+ "DDF598A22B8242AC4E34E70704DBA7B7B73DC3E067C1C98764F8791F84C99156"
+ "947D1FFC875F36FCE24B89369C1B5BF1D4C999DCA28E72A528D0E0163C66C067"
+ "E71B5E0025C13DA93313942F9EDA230B3ADC254821A4CB1A5DC9D0C5F4DC4E8E"
+ "CE46B7B8C72D3C5923C9B30DF1EF7B4EDEDA8BD05C86CA0162AE1BF8F277878E"
+ "607401BAA8F06E3EA873FA4C137324C4E0699277CDF649FE7F0F01945EE25FA7"
+ "0E4A89737E58185B11B4CB52FD5B0497D3E3CD1CEE7B1FBB3E969DB6F4C324A1"
+ "32DC6A0EA21F41332435FD99140C286F8ABBBA926953ADBEED17D30AAD953909"
+ "1347EF6D87163D6B1FF32D8B11FFB2E69FAEE7FE913D3826FBA7F9D11E0E3C57"
+ "27625B37D213710B5DD8965DAEFD3F491E8C029E2BF361039949BADEC31D60AC"
+ "355F26EE41339C03CC9D9B01C3C7F288F0E9D6DFEE78231BDA9AC10FED135913"
+ "2836B1A17CE060742B7E5B738A7177CCD59F70337BA251409C377A0FA5333204"
+ "D8622BA8C06DE0BEF4F32B6D4D77BE9DE977445D8A2A08C5C38341CB7974FBFB"
+ "22C8F983A7D6CEF068DDB2281E6673453521C831C1826861005AE5F37649BC64"
+ "0A6360B23284861441A440F1C5AADE1AB53CA63DB17F4C314D493C4C44DE5F20"
+ "75E084D080F92791F30BDD88373D50AB5A07BC72B0E7FFFA593103964E55603E"
+ "F7FEB7CA0762A1A7B86B6CCAD88CD6CBC7C6935D21F5F06B2700588A2530E619"
+ "DA1648AC809F3DDF56ACE5951737568FFEC7E2AB1AA0AE01B03A7F5A29CE73C0"
+ "5D2801B17CAAD0121082E9952FAB16BA1C386336C62D4CF3A5019CF61609433E"
+ "1C083237D47C4CF575097F7BF9000EF6B6C497A44E6480154A35669AD276BF05"
+ "6CC730B4E5962B6AF96CC6D236AE85CEFDA6877173F72D2F614F6696D1F9DF07"
+ "E107758B0978F69BC9DBE0CCBF252C40A3FDF7CE9104D3344F7B73593CCD73E0";
private static final String IKE_AUTH_RESP_FRAG_2 =
"46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000000F0000000D4"
+ "00020002155211EA41B37BC5F20568A6AE57038EEE208F94F9B444004F1EF391"
+ "2CABFCF857B9CD95FAAA9489ED10A3F5C93510820E22E23FC55ED8049E067D72"
+ "3645C00E1E08611916CE72D7F0A84123B63A8F3B9E78DBBE39967B7BB074AF4D"
+ "BF2178D991EDBDD01908A14A266D09236DB963B14AC33D894F0F83A580209EFD"
+ "61875BB56273AA336C22D6A4D890B93E0D42435667830CC32E4F608500E18569"
+ "3E6C1D88C0B5AE427333C86468E3474DAA4D1506AAB2A4021309A33DD759D0D0"
+ "A8C98BF7FBEA8109361A9F194D0FD756";
private static final String DELETE_IKE_RESP =
"46B8ECA1E0D72A18BF3FA1C2CB1EE86F2E202520000000020000004C00000030"
+ "342842D8DA37C8EFB92ED37C4FBB23CBDC90445137D6A0AF489F9F03641DBA9D"
+ "02F6F59FD8A7A78C7261CEB8";
// Using IPv4 for transport mode Child SA. IPv6 is currently infeasible because the IKE server
// that generates the test vectors is running in an IPv4 only network.
private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS =
new IkeTrafficSelector(
MIN_PORT,
MAX_PORT,
InetAddresses.parseNumericAddress("172.58.35.103"),
InetAddresses.parseNumericAddress("172.58.35.103"));
// TODO(b/157510502): Add test for IKE Session setup with transport mode Child in IPv6 network
private static final String LOCAL_ID_ASN1_DN =
"CN=client.test.ike.android.net, O=Android, C=US";
private static final String REMOTE_ID_ASN1_DN =
"CN=server.test.ike.android.net, O=Android, C=US";
private static X509Certificate sServerCaCert;
private static X509Certificate sClientEndCert;
private static X509Certificate sClientIntermediateCaCertOne;
private static X509Certificate sClientIntermediateCaCertTwo;
private static RSAPrivateKey sClientPrivateKey;
@BeforeClass
public static void setUpCertsBeforeClass() throws Exception {
sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem");
sClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem");
sClientIntermediateCaCertOne =
CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem");
sClientIntermediateCaCertTwo =
CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem");
sClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key");
}
private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) {
IkeSessionParams ikeParams =
new IkeSessionParams.Builder(sContext)
.setNetwork(mTunNetwork)
.setServerHostname(remoteAddress.getHostAddress())
.addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher())
.addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher())
.setLocalIdentification(
new IkeDerAsn1DnIdentification(new X500Principal(LOCAL_ID_ASN1_DN)))
.setRemoteIdentification(
new IkeDerAsn1DnIdentification(
new X500Principal(REMOTE_ID_ASN1_DN)))
.setAuthDigitalSignature(
sServerCaCert,
sClientEndCert,
Arrays.asList(
sClientIntermediateCaCertOne, sClientIntermediateCaCertTwo),
sClientPrivateKey)
.build();
return new IkeSession(
sContext,
ikeParams,
buildTransportModeChildParamsWithTs(
TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS),
mUserCbExecutor,
mIkeSessionCallback,
mFirstChildSessionCallback);
}
@Test
public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception {
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
performSetupIkeAndFirstChildBlocking(
IKE_INIT_RESP,
EXPECTED_AUTH_REQ_FRAG_COUNT /* expectedReqPktCnt */,
true /* expectedAuthUseEncap */,
IKE_AUTH_RESP_FRAG_1,
IKE_AUTH_RESP_FRAG_2);
// IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2
int expectedMsgId = 2;
verifyIkeSessionSetupBlocking();
verifyChildSessionSetupBlocking(
mFirstChildSessionCallback,
Arrays.asList(TRANSPORT_MODE_INBOUND_TS),
Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS),
new ArrayList<LinkAddress>());
IpSecTransformCallRecord firstTransformRecordA =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
IpSecTransformCallRecord firstTransformRecordB =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
// Close IKE Session
ikeSession.close();
performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP);
verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
}
}

View File

@@ -1,220 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import android.net.InetAddresses;
import android.net.LinkAddress;
import android.net.eap.EapSessionConfig;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTrafficSelector;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.net.ipsec.ike.testutils.CertUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Explicitly test setting up transport mode Child SA so that devices do not have
* FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in
* IkeSessionPskTest and authentication method is orthogonal to Child mode.
*/
@RunWith(AndroidJUnit4.class)
public class IkeSessionMschapV2Test extends IkeSessionTestBase {
private static final String IKE_INIT_RESP =
"46B8ECA1E0D72A1873F643FF94D249A921202220000000000000015022000030"
+ "0000002C010100040300000C0100000C800E0080030000080300000203000008"
+ "0200000200000008040000022800008800020000CC6E71E67E32CED6BCE33FBD"
+ "A74113867E3FA3AE21C7C9AB44A7F8835DF602BFD6F6528B67FEE39821232380"
+ "C99E8FFC0A5D767F8F38906DA41946C2299DF18C15FA69BAC08D3EDB32E8C8CA"
+ "28431831561C04CB0CDE393F817151CD8DAF7A311838411F1C39BFDB5EBCF6A6"
+ "1DF66DEB067362649D64607D599B56C4227819D0290000241197004CF31AD00F"
+ "5E0C92E198488D8A2B6F6A25C82762AA49F565BCE9D857D72900001C00004004"
+ "A0D98FEABBFB92A6C0976EE83D2AACFCCF969A6B2900001C0000400575EBF73F"
+ "8EE5CC73917DE9D3F91FCD4A16A0444D290000080000402E290000100000402F"
+ "00020003000400050000000800004014";
private static final String IKE_AUTH_RESP_1_FRAG_1 =
"46B8ECA1E0D72A1873F643FF94D249A93520232000000001000004E0240004C4"
+ "00010002C4159CB756773B3F1911F4595107BC505D7A28C72F05182966076679"
+ "CA68ED92E4BC5CD441C9CB315F2F449A8A521CAFED3C5F285E295FC3791D3415"
+ "E3BACF66A08410DF4E35F7D88FE40DA28851C91C77A6549E186AC1B7846DF3FA"
+ "0A347A5ABBCAEE19E70F0EE5966DC6242A115F29523709302EDAD2E36C8F0395"
+ "CF5C42EC2D2898ECDD8A6AEDD686A70B589A981558667647F32F41E0D8913E94"
+ "A6693F53E59EA8938037F562CF1DC5E6E2CDC630B5FFB08949E3172249422F7D"
+ "EA069F9BAD5F96E48BADC7164A9269669AD0DF295A80C54D1D23CEA3F28AC485"
+ "86D2A9850DA23823037AB7D1577B7B2364C92C36B84238357129EB4A64D33310"
+ "B95DCD50CD53E78C32EFE7DC1627D9432E9BFDEE130045DE967B19F92A9D1270"
+ "F1E2C6BFBAA56802F3E63510578EF1ECB6872852F286EEC790AA1FE0CAF391CB"
+ "E276554922713BA4770CFE71E23F043DC620E22CC02A74F60725D18331B7F2C9"
+ "276EB6FBB7CBDAA040046D7ECBE1A5D7064E04E542807C5101B941D1C81B9D5E"
+ "90347B22BD4E638E2EDC98E369B51AA29BDB2CF8AA610D4B893EB83A4650717C"
+ "38B4D145EE939C18DCEDF6C79933CEB3D7C116B1F188DF9DDD560951B54E4A7D"
+ "80C999A32AB02BF39D7B498DAD36F1A5CBE2F64557D6401AE9DD6E0CEADA3F90"
+ "540FE9114BB6B8719C9064796354F4A180A6600CAD092F8302564E409B71ACB7"
+ "590F19B3AC88E7A606C718D0B97F7E4B4830F11D851C59F2255846DA22E2C805"
+ "0CA2AF2ACF3B6C769D11B75B5AC9AB82ED3D90014994B1BF6FED58FBEF2D72EF"
+ "8BDFE51F9A101393A7CA1ACF78FAEBF3E3CC25E09407D1E14AF351A159A13EE3"
+ "9B919BA8B49942792E7527C2FB6D418C4DF427669A4BF5A1AFBBB973BAF17918"
+ "9C9D520CAC2283B89A539ECE785EBE48FBB77D880A17D55C84A51F46068A4B87"
+ "FF48FEEE50E1E034CC8AFF5DA92105F55EC4823E67BDFE942CA8BE0DAECBBD52"
+ "E8AAF306049DC6C4CF87D987B0AC54FCE92E6AE8507965AAAC6AB8BD3405712F"
+ "EE170B70BC64BDCBD86D80C7AAAF341131F9A1210D7430B17218413AE1363183"
+ "5C98FA2428B1E9E987ADC9070E232310A28F4C3163E18366FFB112BADD7C5E0F"
+ "D13093A7C1428F87856BA0A7E46955589ACA267CE7A04320C4BCDBB60C672404"
+ "778F8D511AAB09349DAB482445D7F606F28E7FBBB18FC0F4EC0AF04F44C282F9"
+ "39C6E3B955C84DADEA350667236583069B74F492D600127636FA31F63E560851"
+ "2FC28B8EA5B4D01D110990B6EA46B9C2E7C7C856C240EF7A8147BA2C4344B85A"
+ "453C862024B5B6814D13CDEAEF7683D539BB50CAFFC0416F269F2F9EDEC5FA30"
+ "022FD7B4B186CD2020E7ED8D81ED90822EDD8B76F840DD68F09694CFF9B4F33E"
+ "11DF4E601A4212881A6D4E9259001705C41E9E23D18A7F3D4A3463649A38211A"
+ "5A90D0F17739A677C74E23F31C01D60B5A0F1E6A4D44FED9D25BF1E63418E1FC"
+ "0B19F6F4B71DE53C62B14B82279538A82DD4BE19AB6E00AFC20F124AAB7DF21A"
+ "42259BE4F40EC69B16917256F23E2C37376311D62E0A3A0EF8C2AD0C090221D5"
+ "C5ECA08F08178A4D31FFDB150C609827D18AD83C7B0A43AEE0406BD3FB494B53"
+ "A279FDD6447E234C926AD8CE47FFF779BB45B1FC8457C6E7D257D1359959D977"
+ "CEF6906A3367DC4D454993EFDC6F1EA94E17EB3DCB00A289346B4CFD7F19B16E";
private static final String IKE_AUTH_RESP_1_FRAG_2 =
"46B8ECA1E0D72A1873F643FF94D249A935202320000000010000008000000064"
+ "00020002C61F66025E821A5E69A4DE1F591A2C32C983C3154A5003660137D685"
+ "A5262B9FDF5EDC699DE4D8BD38F549E3CBD12024B45B4C86561C36C3EED839DA"
+ "9860C6AA0B764C662D08F1B6A98F68CF6E3038F737C0B415AD8A8B7D702BD92A";
private static final String IKE_AUTH_RESP_2 =
"46B8ECA1E0D72A1873F643FF94D249A92E202320000000020000008C30000070"
+ "62B90C2229FD23025BC2FD7FE6341E9EE04B17264CD619BCE18975A5F88BE438"
+ "D4AD4A5310057255AF568C293A29B10107E3EE3675C10AA2B26404D90C0528CC"
+ "F7605A86C96A1F2635CCC6CFC90EE65E5C2A2262EB33FE520EB708423A83CB63"
+ "274ECCBB102AF5DF35742657";
private static final String IKE_AUTH_RESP_3 =
"46B8ECA1E0D72A1873F643FF94D249A92E202320000000030000004C30000030"
+ "AB52C3C80123D3432C05AF457CE93C352395F73E861CD49561BA528CFE68D17D"
+ "78BBF6FC41E81C2B9EA051A2";
private static final String IKE_AUTH_RESP_4 =
"46B8ECA1E0D72A1873F643FF94D249A92E20232000000004000000CC270000B0"
+ "8D3342A7AB2666AC754F4B55C5C6B1A61255E62FBCA53D5CDEEDE60DADB7915C"
+ "7F962076A58BF7D39A05ED1B60FF349B6DE311AF7CEBC72B4BB9723A728A5D3E"
+ "9E508B2D7A11843D279B56ADA07E608D61F5CA7638F10372A440AD1DCE44E190"
+ "7B7B7A68B126EBBB86638D667D5B528D233BA8D32D7E0FAC4E1448E87396EEE6"
+ "0985B79841E1229D7962AACFD8F872722EC8D5B19D4C82D6C4ADCB276127A1A7"
+ "3FC84CDF85B2299BC96B64AC";
private static final String DELETE_IKE_RESP =
"46B8ECA1E0D72A1873F643FF94D249A92E202520000000050000004C00000030"
+ "622CE06C8CB132AA00567E9BC83F58B32BD7DB5130C76E385B306434DA227361"
+ "D50CC19D408A8D4F36F9697F";
// This value is align with the test vectors hex that are generated in an IPv4 environment
private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS =
new IkeTrafficSelector(
MIN_PORT,
MAX_PORT,
InetAddresses.parseNumericAddress("172.58.35.67"),
InetAddresses.parseNumericAddress("172.58.35.67"));
private static final EapSessionConfig EAP_CONFIG =
new EapSessionConfig.Builder()
.setEapIdentity(EAP_IDENTITY)
.setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD)
.build();
private static X509Certificate sServerCaCert;
@BeforeClass
public static void setUpCertBeforeClass() throws Exception {
sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem");
}
private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) {
IkeSessionParams ikeParams =
new IkeSessionParams.Builder(sContext)
.setNetwork(mTunNetwork)
.setServerHostname(remoteAddress.getHostAddress())
.addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher())
.addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher())
.setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME))
.setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME))
.setAuthEap(sServerCaCert, EAP_CONFIG)
.build();
return new IkeSession(
sContext,
ikeParams,
buildTransportModeChildParamsWithTs(
TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS),
mUserCbExecutor,
mIkeSessionCallback,
mFirstChildSessionCallback);
}
@Test
public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception {
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
int expectedMsgId = 0;
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
false /* expectedUseEncap */,
IKE_INIT_RESP);
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
true /* expectedUseEncap */,
IKE_AUTH_RESP_1_FRAG_1,
IKE_AUTH_RESP_1_FRAG_2);
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
true /* expectedUseEncap */,
IKE_AUTH_RESP_2);
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
true /* expectedUseEncap */,
IKE_AUTH_RESP_3);
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
true /* expectedUseEncap */,
IKE_AUTH_RESP_4);
verifyIkeSessionSetupBlocking();
verifyChildSessionSetupBlocking(
mFirstChildSessionCallback,
Arrays.asList(TRANSPORT_MODE_INBOUND_TS),
Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS),
new ArrayList<LinkAddress>());
IpSecTransformCallRecord firstTransformRecordA =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
IpSecTransformCallRecord firstTransformRecordB =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
// Close IKE Session
ikeSession.close();
performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP);
verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
}
}

View File

@@ -1,414 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static android.telephony.TelephonyManager.APPTYPE_USIM;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.net.eap.EapSessionConfig;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeIdentification;
import android.net.ipsec.ike.IkeSaProposal;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer;
import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer;
import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.net.ipsec.ike.testutils.CertUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public final class IkeSessionParamsTest extends IkeSessionTestBase {
private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(20L);
private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(10L);
private static final int DPD_DELAY_SECONDS = (int) TimeUnit.MINUTES.toSeconds(10L);
private static final int[] RETRANS_TIMEOUT_MS_LIST = new int[] {500, 500, 500, 500, 500, 500};
private static final Map<Class<? extends IkeConfigRequest>, Integer> EXPECTED_REQ_COUNT =
new HashMap<>();
private static final HashSet<InetAddress> EXPECTED_PCSCF_SERVERS = new HashSet<>();
static {
EXPECTED_REQ_COUNT.put(ConfigRequestIpv4PcscfServer.class, 3);
EXPECTED_REQ_COUNT.put(ConfigRequestIpv6PcscfServer.class, 3);
EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_1);
EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_2);
EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_1);
EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_2);
}
// Arbitrary proposal and remote ID. Local ID is chosen to match the client end cert in the
// following CL
private static final IkeSaProposal SA_PROPOSAL =
SaProposalTest.buildIkeSaProposalWithNormalModeCipher();
private static final IkeIdentification LOCAL_ID = new IkeFqdnIdentification(LOCAL_HOSTNAME);
private static final IkeIdentification REMOTE_ID = new IkeFqdnIdentification(REMOTE_HOSTNAME);
private static final EapSessionConfig EAP_ALL_METHODS_CONFIG =
createEapOnlySafeMethodsBuilder()
.setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD)
.build();
private static final EapSessionConfig EAP_ONLY_SAFE_METHODS_CONFIG =
createEapOnlySafeMethodsBuilder().build();
private X509Certificate mServerCaCert;
private X509Certificate mClientEndCert;
private X509Certificate mClientIntermediateCaCertOne;
private X509Certificate mClientIntermediateCaCertTwo;
private RSAPrivateKey mClientPrivateKey;
@Before
public void setUp() throws Exception {
// This address is never used except for setting up the test network
setUpTestNetwork(IPV4_ADDRESS_LOCAL);
mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem");
mClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem");
mClientIntermediateCaCertOne =
CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem");
mClientIntermediateCaCertTwo =
CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem");
mClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key");
}
@After
public void tearDown() throws Exception {
tearDownTestNetwork();
}
private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() {
return new EapSessionConfig.Builder()
.setEapIdentity(EAP_IDENTITY)
.setEapSimConfig(SUB_ID, APPTYPE_USIM)
.setEapAkaConfig(SUB_ID, APPTYPE_USIM)
.setEapAkaPrimeConfig(
SUB_ID, APPTYPE_USIM, NETWORK_NAME, true /* allowMismatchedNetworkNames */);
}
/**
* Create a Builder that has minimum configurations to build an IkeSessionParams.
*
* <p>Authentication method is arbitrarily selected. Using other method (e.g. setAuthEap) also
* works.
*/
private IkeSessionParams.Builder createIkeParamsBuilderMinimum() {
return new IkeSessionParams.Builder(sContext)
.setNetwork(mTunNetwork)
.setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress())
.addSaProposal(SA_PROPOSAL)
.setLocalIdentification(LOCAL_ID)
.setRemoteIdentification(REMOTE_ID)
.setAuthPsk(IKE_PSK);
}
/**
* Verify the minimum configurations to build an IkeSessionParams.
*
* @see #createIkeParamsBuilderMinimum
*/
private void verifyIkeParamsMinimum(IkeSessionParams sessionParams) {
assertEquals(mTunNetwork, sessionParams.getNetwork());
assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname());
assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals());
assertEquals(LOCAL_ID, sessionParams.getLocalIdentification());
assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification());
IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
assertTrue(localConfig instanceof IkeAuthPskConfig);
assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk());
IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
assertTrue(remoteConfig instanceof IkeAuthPskConfig);
assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk());
}
@Test
public void testBuildWithMinimumSet() throws Exception {
IkeSessionParams sessionParams = createIkeParamsBuilderMinimum().build();
verifyIkeParamsMinimum(sessionParams);
// Verify default values that do not need explicit configuration. Do not do assertEquals
// to be avoid being a change-detector test
assertTrue(sessionParams.getHardLifetimeSeconds() > sessionParams.getSoftLifetimeSeconds());
assertTrue(sessionParams.getSoftLifetimeSeconds() > 0);
assertTrue(sessionParams.getDpdDelaySeconds() > 0);
assertTrue(sessionParams.getRetransmissionTimeoutsMillis().length > 0);
for (int timeout : sessionParams.getRetransmissionTimeoutsMillis()) {
assertTrue(timeout > 0);
}
assertTrue(sessionParams.getConfigurationRequests().isEmpty());
assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
}
@Test
public void testSetLifetimes() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimum()
.setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS)
.build();
verifyIkeParamsMinimum(sessionParams);
assertEquals(HARD_LIFETIME_SECONDS, sessionParams.getHardLifetimeSeconds());
assertEquals(SOFT_LIFETIME_SECONDS, sessionParams.getSoftLifetimeSeconds());
}
@Test
public void testSetDpdDelay() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimum().setDpdDelaySeconds(DPD_DELAY_SECONDS).build();
verifyIkeParamsMinimum(sessionParams);
assertEquals(DPD_DELAY_SECONDS, sessionParams.getDpdDelaySeconds());
}
@Test
public void testSetRetransmissionTimeouts() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimum()
.setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST)
.build();
verifyIkeParamsMinimum(sessionParams);
assertArrayEquals(RETRANS_TIMEOUT_MS_LIST, sessionParams.getRetransmissionTimeoutsMillis());
}
@Test
public void testSetPcscfConfigRequests() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimum()
.setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST)
.addPcscfServerRequest(AF_INET)
.addPcscfServerRequest(PCSCF_IPV4_ADDRESS_1)
.addPcscfServerRequest(PCSCF_IPV6_ADDRESS_1)
.addPcscfServerRequest(AF_INET6)
.addPcscfServerRequest(PCSCF_IPV4_ADDRESS_2)
.addPcscfServerRequest(PCSCF_IPV6_ADDRESS_2)
.build();
verifyIkeParamsMinimum(sessionParams);
verifyConfigRequestTypes(EXPECTED_REQ_COUNT, sessionParams.getConfigurationRequests());
Set<InetAddress> resultAddresses = new HashSet<>();
for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) {
if (req instanceof ConfigRequestIpv4PcscfServer
&& ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) {
resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress());
} else if (req instanceof ConfigRequestIpv6PcscfServer
&& ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) {
resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress());
}
}
assertEquals(EXPECTED_PCSCF_SERVERS, resultAddresses);
}
@Test
public void testAddIkeOption() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimum()
.addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
.build();
verifyIkeParamsMinimum(sessionParams);
assertTrue(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
}
@Test
public void testRemoveIkeOption() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimum()
.addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
.removeIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
.build();
verifyIkeParamsMinimum(sessionParams);
assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
}
/**
* Create a Builder that has minimum configurations to build an IkeSessionParams, except for
* authentication method.
*/
private IkeSessionParams.Builder createIkeParamsBuilderMinimumWithoutAuth() {
return new IkeSessionParams.Builder(sContext)
.setNetwork(mTunNetwork)
.setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress())
.addSaProposal(SA_PROPOSAL)
.setLocalIdentification(LOCAL_ID)
.setRemoteIdentification(REMOTE_ID);
}
/**
* Verify the minimum configurations to build an IkeSessionParams, except for authentication
* method.
*
* @see #createIkeParamsBuilderMinimumWithoutAuth
*/
private void verifyIkeParamsMinimumWithoutAuth(IkeSessionParams sessionParams) {
assertEquals(mTunNetwork, sessionParams.getNetwork());
assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname());
assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals());
assertEquals(LOCAL_ID, sessionParams.getLocalIdentification());
assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification());
}
@Test
public void testBuildWithPsk() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimumWithoutAuth().setAuthPsk(IKE_PSK).build();
verifyIkeParamsMinimumWithoutAuth(sessionParams);
IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
assertTrue(localConfig instanceof IkeAuthPskConfig);
assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk());
IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
assertTrue(remoteConfig instanceof IkeAuthPskConfig);
assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk());
}
@Test
public void testBuildWithEap() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimumWithoutAuth()
.setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG)
.build();
verifyIkeParamsMinimumWithoutAuth(sessionParams);
IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
assertTrue(localConfig instanceof IkeAuthEapConfig);
assertEquals(EAP_ALL_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig());
IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
assertEquals(
mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert());
}
@Test
public void testBuildWithEapOnlyAuth() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimumWithoutAuth()
.setAuthEap(mServerCaCert, EAP_ONLY_SAFE_METHODS_CONFIG)
.addIkeOption(IKE_OPTION_EAP_ONLY_AUTH)
.build();
assertTrue(sessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH));
verifyIkeParamsMinimumWithoutAuth(sessionParams);
IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
assertTrue(localConfig instanceof IkeAuthEapConfig);
assertEquals(EAP_ONLY_SAFE_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig());
IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
assertEquals(
mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert());
}
@Test
public void testThrowBuildEapOnlyAuthWithUnsafeMethod() throws Exception {
try {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimumWithoutAuth()
.setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG)
.addIkeOption(IKE_OPTION_EAP_ONLY_AUTH)
.build();
fail("Expected to fail because EAP only unsafe method is proposed");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testBuildWithDigitalSignature() throws Exception {
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimumWithoutAuth()
.setAuthDigitalSignature(mServerCaCert, mClientEndCert, mClientPrivateKey)
.build();
verifyIkeParamsMinimumWithoutAuth(sessionParams);
IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig);
IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig;
assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate());
assertEquals(Collections.EMPTY_LIST, localSignConfig.getIntermediateCertificates());
assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey());
IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
assertEquals(
mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert());
}
@Test
public void testBuildWithDigitalSignatureAndIntermediateCerts() throws Exception {
List<X509Certificate> intermediateCerts =
Arrays.asList(mClientIntermediateCaCertOne, mClientIntermediateCaCertTwo);
IkeSessionParams sessionParams =
createIkeParamsBuilderMinimumWithoutAuth()
.setAuthDigitalSignature(
mServerCaCert, mClientEndCert, intermediateCerts, mClientPrivateKey)
.build();
verifyIkeParamsMinimumWithoutAuth(sessionParams);
IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig);
IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig;
assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate());
assertEquals(intermediateCerts, localSignConfig.getIntermediateCertificates());
assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey());
IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
assertEquals(
mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert());
}
}

View File

@@ -1,371 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS;
import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN;
import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import android.net.LinkAddress;
import android.net.ipsec.ike.ChildSessionParams;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.platform.test.annotations.AppModeFull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@AppModeFull(reason = "MANAGE_IPSEC_TUNNELS permission can't be granted to instant apps")
public class IkeSessionPskTest extends IkeSessionTestBase {
// Test vectors for success workflow
private static final String SUCCESS_IKE_INIT_RESP =
"46B8ECA1E0D72A18B45427679F9245D421202220000000000000015022000030"
+ "0000002C010100040300000C0100000C800E0080030000080300000203000008"
+ "0200000200000008040000022800008800020000A7AA3435D088EC1A2B7C2A47"
+ "1FA1B85F1066C9B2006E7C353FB5B5FDBC2A88347ED2C6F5B7A265D03AE34039"
+ "6AAC0145CFCC93F8BDB219DDFF22A603B8856A5DC59B6FAB7F17C5660CF38670"
+ "8794FC72F273ADEB7A4F316519794AED6F8AB61F95DFB360FAF18C6C8CABE471"
+ "6E18FE215348C2E582171A57FC41146B16C4AFE429000024A634B61C0E5C90C6"
+ "8D8818B0955B125A9B1DF47BBD18775710792E651083105C2900001C00004004"
+ "406FA3C5685A16B9B72C7F2EEE9993462C619ABE2900001C00004005AF905A87"
+ "0A32222AA284A7070585601208A282F0290000080000402E290000100000402F"
+ "00020003000400050000000800004014";
private static final String SUCCESS_IKE_AUTH_RESP =
"46B8ECA1E0D72A18B45427679F9245D42E20232000000001000000EC240000D0"
+ "0D06D37198F3F0962DE8170D66F1A9008267F98CDD956D984BDCED2FC7FAF84A"
+ "A6664EF25049B46B93C9ED420488E0C172AA6635BF4011C49792EF2B88FE7190"
+ "E8859FEEF51724FD20C46E7B9A9C3DC4708EF7005707A18AB747C903ABCEAC5C"
+ "6ECF5A5FC13633DCE3844A920ED10EF202F115DBFBB5D6D2D7AB1F34EB08DE7C"
+ "A54DCE0A3A582753345CA2D05A0EFDB9DC61E81B2483B7D13EEE0A815D37252C"
+ "23D2F29E9C30658227D2BB0C9E1A481EAA80BC6BE9006BEDC13E925A755A0290"
+ "AEC4164D29997F52ED7DCC2E";
private static final String SUCCESS_CREATE_CHILD_RESP =
"46B8ECA1E0D72A18B45427679F9245D42E20242000000002000000CC210000B0"
+ "484565D4AF6546274674A8DE339E9C9584EE2326AB9260F41C4D0B6C5B02D1D"
+ "2E8394E3CDE3094895F2ACCABCDCA8E82960E5196E9622BD13745FC8D6A2BED"
+ "E561FF5D9975421BC463C959A3CBA3478256B6D278159D99B512DDF56AC1658"
+ "63C65A986F395FE8B1476124B91F83FD7865304EB95B22CA4DD9601DA7A2533"
+ "ABF4B36EB1B8CD09522F6A600032316C74E562E6756D9D49D945854E2ABDC4C"
+ "3AF36305353D60D40B58BE44ABF82";
private static final String SUCCESS_DELETE_CHILD_RESP =
"46B8ECA1E0D72A18B45427679F9245D42E202520000000030000004C2A000030"
+ "0C5CEB882DBCA65CE32F4C53909335F1365C91C555316C5E9D9FB553F7AA916"
+ "EF3A1D93460B7FABAF0B4B854";
private static final String SUCCESS_DELETE_IKE_RESP =
"46B8ECA1E0D72A18B45427679F9245D42E202520000000040000004C00000030"
+ "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8"
+ "6743A7CEB2BE34AC00095A5B8";
private IkeSession openIkeSessionWithTunnelModeChild(InetAddress remoteAddress) {
return openIkeSession(remoteAddress, buildTunnelModeChildSessionParams());
}
private IkeSession openIkeSessionWithTransportModeChild(InetAddress remoteAddress) {
return openIkeSession(remoteAddress, buildTransportModeChildParamsWithDefaultTs());
}
private IkeSession openIkeSession(InetAddress remoteAddress, ChildSessionParams childParams) {
IkeSessionParams ikeParams =
new IkeSessionParams.Builder(sContext)
.setNetwork(mTunNetwork)
.setServerHostname(remoteAddress.getHostAddress())
.addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher())
.addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher())
.setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME))
.setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME))
.setAuthPsk(IKE_PSK)
.build();
return new IkeSession(
sContext,
ikeParams,
childParams,
mUserCbExecutor,
mIkeSessionCallback,
mFirstChildSessionCallback);
}
@BeforeClass
public static void setUpTunnelPermissionBeforeClass() throws Exception {
// Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and
// a standard permission is insufficient. So we shell out the appop, to give us the
// right appop permissions.
setAppOp(OP_MANAGE_IPSEC_TUNNELS, true);
}
// This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass
// methods.
@AfterClass
public static void tearDownTunnelPermissionAfterClass() throws Exception {
setAppOp(OP_MANAGE_IPSEC_TUNNELS, false);
}
@Test
public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception {
if (!hasTunnelsFeature()) return;
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress);
performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP);
// IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2
int expectedMsgId = 2;
verifyIkeSessionSetupBlocking();
verifyChildSessionSetupBlocking(
mFirstChildSessionCallback,
Arrays.asList(TUNNEL_MODE_INBOUND_TS),
Arrays.asList(TUNNEL_MODE_OUTBOUND_TS),
Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR));
IpSecTransformCallRecord firstTransformRecordA =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
IpSecTransformCallRecord firstTransformRecordB =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
// Open additional Child Session
TestChildSessionCallback additionalChildCb = new TestChildSessionCallback();
ikeSession.openChildSession(buildTunnelModeChildSessionParams(), additionalChildCb);
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
true /* expectedUseEncap */,
SUCCESS_CREATE_CHILD_RESP);
// Verify opening additional Child Session
verifyChildSessionSetupBlocking(
additionalChildCb,
Arrays.asList(TUNNEL_MODE_INBOUND_TS),
Arrays.asList(TUNNEL_MODE_OUTBOUND_TS),
new ArrayList<LinkAddress>());
IpSecTransformCallRecord additionalTransformRecordA =
additionalChildCb.awaitNextCreatedIpSecTransform();
IpSecTransformCallRecord additionalTransformRecordB =
additionalChildCb.awaitNextCreatedIpSecTransform();
verifyCreateIpSecTransformPair(additionalTransformRecordA, additionalTransformRecordB);
// Close additional Child Session
ikeSession.closeChildSession(additionalChildCb);
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
true /* expectedUseEncap */,
SUCCESS_DELETE_CHILD_RESP);
verifyDeleteIpSecTransformPair(
additionalChildCb, additionalTransformRecordA, additionalTransformRecordB);
additionalChildCb.awaitOnClosed();
// Close IKE Session
ikeSession.close();
performCloseIkeBlocking(expectedMsgId++, SUCCESS_DELETE_IKE_RESP);
verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
}
@Test
public void testIkeSessionSetupAndChildSessionSetupWithTunnelModeV6() throws Exception {
if (!hasTunnelsFeature()) return;
final String ikeInitResp =
"46B8ECA1E0D72A186F7B6C2CEB77EB9021202220000000000000011822000030"
+ "0000002C010100040300000C0100000C800E0100030000080300000C03000008"
+ "0200000500000008040000022800008800020000DABAA04B38B491E2403F2125"
+ "96ECF1C8EF7B1DC19A422FDD46E1756C826BB3A16404361B775D9950577B5CDF"
+ "6AAA1642BD1427BDA8BC55354A97C1025E19C1E2EE2DF8A0C9406E545D829F52"
+ "75695008E3B742984B8DD1770F3514213B0DF3EE8B199416DF200D248115C057"
+ "1C193E4F96802E5EF48DD99CAC251882A8F7CCC329000024BC6F0F1D3653C2C7"
+ "679E02CDB6A3B32B2FEE9AF52F0326D4D9AE073D56CE8922290000080000402E"
+ "290000100000402F00020003000400050000000800004014";
final String ikeAuthResp =
"46B8ECA1E0D72A186F7B6C2CEB77EB902E202320000000010000015024000134"
+ "4D115AFDCDAD0310760BB664EB7D405A340869AD6EDF0AAEAD0663A9253DADCB"
+ "73EBE5CD29D4FA1CDEADE0B94391B5C4CF77BCC1596ACE3CE6A7891E44888FA5"
+ "46632C0EF4E6193C023C9DC59142C37D1C49D6EF5CD324EC6FC35C89E1721C78"
+ "91FDCDB723D8062709950F4AA9273D26A54C9C7E86862DBC15F7B6641D2B9BAD"
+ "E55069008201D12968D97B537B1518FE87B0FFA03C3EE6012C06721B1E2A3F68"
+ "92108BC4A4F7063F7F94562D8B60F291A1377A836CF12BCDA7E15C1A8F3C77BB"
+ "6DB7F2C833CCE4CDDED7506536621A3356CE2BC1874E7B1A1A9B447D7DF6AB09"
+ "638B8AD94A781B28BB91B514B611B24DF8E8A047A10AE27BBF15C754D3D2F792"
+ "D3E1CCADDAE934C98AE53A8FC3419C88AFF0355564F82A629C998012DA7BB704"
+ "5307270DF326377E3E1994476902035B";
final String deleteIkeResp =
"46B8ECA1E0D72A186F7B6C2CEB77EB902E202520000000020000005000000034"
+ "CF15C299F35688E5140A48B61C95F004121BF8236201415E5CD45BA41AAB16D4"
+ "90B44B9E6D5D92B5B97D24196A58C73F";
mLocalAddress = IPV6_ADDRESS_LOCAL;
mRemoteAddress = IPV6_ADDRESS_REMOTE;
// Teardown current test network that uses IPv4 address and set up new network with IPv6
// address.
tearDownTestNetwork();
setUpTestNetwork(mLocalAddress);
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress);
performSetupIkeAndFirstChildBlocking(
ikeInitResp,
1 /* expectedAuthReqPktCnt */,
false /* expectedAuthUseEncap */,
ikeAuthResp);
// Local request message ID starts from 2 because there is one IKE_INIT message and a single
// IKE_AUTH message.
int expectedMsgId = 2;
verifyIkeSessionSetupBlocking();
verifyChildSessionSetupBlocking(
mFirstChildSessionCallback,
Arrays.asList(TUNNEL_MODE_INBOUND_TS_V6),
Arrays.asList(TUNNEL_MODE_OUTBOUND_TS_V6),
Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR_V6),
Arrays.asList(EXPECTED_DNS_SERVERS_ONE, EXPECTED_DNS_SERVERS_TWO));
IpSecTransformCallRecord firstTransformRecordA =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
IpSecTransformCallRecord firstTransformRecordB =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
// Close IKE Session
ikeSession.close();
performCloseIkeBlocking(expectedMsgId++, false /* expectedUseEncap */, deleteIkeResp);
verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
}
@Test
public void testIkeSessionKillWithTunnelMode() throws Exception {
if (!hasTunnelsFeature()) return;
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress);
performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP);
ikeSession.kill();
mFirstChildSessionCallback.awaitOnClosed();
mIkeSessionCallback.awaitOnClosed();
}
@Test
public void testIkeInitFail() throws Exception {
final String ikeInitFailRespHex =
"46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E";
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress);
int expectedMsgId = 0;
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
false /* expectedUseEncap */,
ikeInitFailRespHex);
mFirstChildSessionCallback.awaitOnClosed();
IkeProtocolException protocolException =
(IkeProtocolException) mIkeSessionCallback.awaitOnClosedException();
assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, protocolException.getErrorType());
assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData());
}
@Test
public void testIkeAuthHandlesAuthFailNotification() throws Exception {
final String ikeInitRespHex =
"46B8ECA1E0D72A18CF94CE3159486F002120222000000000000001502200"
+ "00300000002C010100040300000C0100000C800E01000300000803000005"
+ "0300000802000004000000080400000228000088000200001821AA854691"
+ "FA3292DF710F0AC149ACBD0CB421608B8796C1912AF04C5B4B23936FDEC4"
+ "7CB640E3EAFB56BBB562825E87AF68B40E4BAB80A49BAD44407450A4195A"
+ "1DD54BD99F48D28C9F0FBA315A3401C1C3C4AD55911F514A8DF2D2467C46"
+ "A73DDC1452AE81336E0F0D5EC896D2E7A77628AF2F9089F48943399DF216"
+ "EFCD2900002418D2B7E4E6AF0FEFF5962CF8D68F7793B1293FEDE13331D4"
+ "AB0CE9436C2EE1EC2900001C0000400457BD9AEF5B362A83DD7F3DDAA4A9"
+ "9B6B4041DAF32900001C000040055A81893582701E44D4B6729A22FE06DE"
+ "82A03A36290000080000402E290000100000402F00020003000400050000"
+ "000800004014";
final String ikeAuthFailRespHex =
"46B8ECA1E0D72A18CF94CE3159486F002E202320000000010000004C2900"
+ "00301B9E4C8242D3BE62E7F0A537FE8B92C6EAB7153105DA421DCE43A06D"
+ "AB6E4808BAC0CA1DAD6ADD0A126A41BD";
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress);
performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthFailRespHex);
mFirstChildSessionCallback.awaitOnClosed();
IkeProtocolException protocolException =
(IkeProtocolException) mIkeSessionCallback.awaitOnClosedException();
assertEquals(ERROR_TYPE_AUTHENTICATION_FAILED, protocolException.getErrorType());
assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData());
}
@Test
public void testIkeAuthHandlesFirstChildCreationFail() throws Exception {
final String ikeInitRespHex =
"46B8ECA1E0D72A18F5ABBF896A1240BE2120222000000000000001502200"
+ "00300000002C010100040300000C0100000C800E0100030000080300000C"
+ "03000008020000050000000804000002280000880002000074950F016B85"
+ "605E57E24651843AB70E41B552EDEE227DFE51E6CBEC00E75FFEFC7D5453"
+ "109B15F721FCD811FC9F113BE06050882F2FC5F5FF25857E555CCFB5AB64"
+ "8B0D1D7A819A3B05DE1FE89A4A627C60D5AA06CD0F66ACD3748722F9CD4F"
+ "F30AE7477CBC12049821F07AD6C9F0ED732321A6A36FA817722E025AC34B"
+ "ABE62900002432E3807F595070E95EDA341A787599B24B1151B535B0222B"
+ "65C003401B9B38F82900001C000040043BB760DB3037B51768DFFAB4B21D"
+ "B1716EA1C1382900001C0000400531098EB04DF1BE3F304606BD59B454A8"
+ "CC7E7311290000080000402E290000100000402F00020003000400050000"
+ "000800004014";
final String ikeAuthCreateChildFailHex =
"46B8ECA1E0D72A18F5ABBF896A1240BE2E20232000000001000000B02400"
+ "009400B0861242E0C88ECB3848D772B560CAD65B6AC9DFFDC8622A394B8E"
+ "64E550BDD69FCD7E768129787ED9062992C1D6DB0F0631C2E05765B403CF"
+ "EF1D0A055B32F6698FF7DB5B8FB1B6A83A81634D00E22C86E35B3BFBEC73"
+ "EAC6806678926945BC7A57003DC1A3528A1EC423EE56C1075B36C0B57A6B"
+ "C6DD990182F6FABFFA167D199C7D629E5B830AAD2AFBD31CEBA6";
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress);
performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthCreateChildFailHex);
// Even though the child creation failed, the authentication succeeded, so the IKE Session's
// onOpened() callback is still expected
verifyIkeSessionSetupBlocking();
// Verify Child Creation failed
IkeProtocolException protocolException =
(IkeProtocolException) mFirstChildSessionCallback.awaitOnClosedException();
assertEquals(ERROR_TYPE_TS_UNACCEPTABLE, protocolException.getErrorType());
assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData());
ikeSession.kill();
mIkeSessionCallback.awaitOnClosed();
}
}

View File

@@ -1,265 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static com.android.internal.util.HexDump.hexStringToByteArray;
import android.net.InetAddresses;
import android.net.LinkAddress;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.cts.IkeTunUtils.PortPair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Explicitly test transport mode Child SA so that devices without FEATURE_IPSEC_TUNNELS can be test
* covered. Tunnel mode Child SA setup has been tested in IkeSessionPskTest. Rekeying process is
* independent from Child SA mode.
*/
@RunWith(AndroidJUnit4.class)
public class IkeSessionRekeyTest extends IkeSessionTestBase {
// This value is align with the test vectors hex that are generated in an IPv4 environment
private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS =
new IkeTrafficSelector(
MIN_PORT,
MAX_PORT,
InetAddresses.parseNumericAddress("172.58.35.40"),
InetAddresses.parseNumericAddress("172.58.35.40"));
private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) {
IkeSessionParams ikeParams =
new IkeSessionParams.Builder(sContext)
.setNetwork(mTunNetwork)
.setServerHostname(remoteAddress.getHostAddress())
.addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher())
.addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher())
.setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME))
.setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME))
.setAuthPsk(IKE_PSK)
.build();
return new IkeSession(
sContext,
ikeParams,
buildTransportModeChildParamsWithTs(
TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS),
mUserCbExecutor,
mIkeSessionCallback,
mFirstChildSessionCallback);
}
private byte[] buildInboundPkt(PortPair outPktSrcDestPortPair, String inboundDataHex)
throws Exception {
// Build inbound packet by flipping the outbound packet addresses and ports
return IkeTunUtils.buildIkePacket(
mRemoteAddress,
mLocalAddress,
outPktSrcDestPortPair.dstPort,
outPktSrcDestPortPair.srcPort,
true /* useEncap */,
hexStringToByteArray(inboundDataHex));
}
@Test
public void testRekeyIke() throws Exception {
final String ikeInitResp =
"46B8ECA1E0D72A1866B5248CF6C7472D21202220000000000000015022000030"
+ "0000002C010100040300000C0100000C800E0100030000080300000C03000008"
+ "0200000500000008040000022800008800020000920D3E830E7276908209212D"
+ "E5A7F2A48706CFEF1BE8CB6E3B173B8B4E0D8C2DC626271FF1B13A88619E569E"
+ "7B03C3ED2C127390749CDC7CDC711D0A8611E4457FFCBC4F0981B3288FBF58EA"
+ "3E8B70E27E76AE70117FBBCB753660ADDA37EB5EB3A81BED6A374CCB7E132C2A"
+ "94BFCE402DC76B19C158B533F6B1F2ABF01ACCC329000024B302CA2FB85B6CF4"
+ "02313381246E3C53828D787F6DFEA6BD62D6405254AEE6242900001C00004004"
+ "7A1682B06B58596533D00324886EF1F20EF276032900001C00004005BF633E31"
+ "F9984B29A62E370BB2770FC09BAEA665290000080000402E290000100000402F"
+ "00020003000400050000000800004014";
final String ikeAuthResp =
"46B8ECA1E0D72A1866B5248CF6C7472D2E20232000000001000000F0240000D4"
+ "10166CA8647F56123DE74C17FA5E256043ABF73216C812EE32EE1BB01EAF4A82"
+ "DC107AB3ADBFEE0DEA5EEE10BDD5D43178F4C975C7C775D252273BB037283C7F"
+ "236FE34A6BCE4833816897075DB2055B9FFD66DFA45A0A89A8F70AFB59431EED"
+ "A20602FB614369D12906D3355CF7298A5D25364ABBCC75A9D88E0E6581449FCD"
+ "4E361A39E00EFD1FD0A69651F63DB46C12470226AA21BA5EFF48FAF0B6DDF61C"
+ "B0A69392CE559495EEDB4D1C1D80688434D225D57210A424C213F7C993D8A456"
+ "38153FBD194C5E247B592D1D048DB4C8";
final String rekeyIkeCreateReq =
"46B8ECA1E0D72A1866B5248CF6C7472D2E202400000000000000013021000114"
+ "13743670039E308A8409BA5FD47B67F956B36FEE88AC3B70BB5D789B8218A135"
+ "1B3D83E260E87B3EDB1BF064F09D4DC2611AEDBC99951B4B2DE767BD4AA2ACC3"
+ "3653549CFC66B75869DF003CDC9A137A9CC27776AD5732B34203E74BE8CA4858"
+ "1D5C0D9C9CA52D680EB299B4B21C7FA25FFEE174D57015E0FF2EAED653AAD95C"
+ "071ABE269A8C2C9FBC1188E07550EB992F910D4CA9689E44BA66DE0FABB2BDF9"
+ "8DD377186DBB25EF9B68B027BB2A27981779D8303D88D7CE860010A42862D50B"
+ "1E0DBFD3D27C36F14809D7F493B2B96A65534CF98B0C32AD5219AD77F681AC04"
+ "9D5CB89A0230A91A243FA7F16251B0D9B4B65E7330BEEAC9663EF4578991EAC8"
+ "46C19EBB726E7D113F1D0D601102C05E";
final String rekeyIkeDeleteReq =
"46B8ECA1E0D72A1866B5248CF6C7472D2E20250000000001000000502A000034"
+ "02E40C0C7B1ED977729F705BB9B643FAC513A1070A6EB28ECD2AEA8A441ADC05"
+ "7841382A7967BBF116AE52496590B2AD";
final String deleteIkeReq =
"7D3DEDC65407D1FC9361C8CF8C47162A2E20250800000000000000502A000034"
+ "201915C9E4E9173AA9EE79F3E02FE2D4954B22085C66D164762C34D347C16E9F"
+ "FC5F7F114428C54D8D915860C57B1BC1";
final long newIkeDeterministicInitSpi = Long.parseLong("7D3DEDC65407D1FC", 16);
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp);
// Local request message ID starts from 2 because there is one IKE_INIT message and a single
// IKE_AUTH message.
int expectedReqMsgId = 2;
int expectedRespMsgId = 0;
verifyIkeSessionSetupBlocking();
verifyChildSessionSetupBlocking(
mFirstChildSessionCallback,
Arrays.asList(TRANSPORT_MODE_INBOUND_TS),
Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS),
new ArrayList<LinkAddress>());
IpSecTransformCallRecord firstTransformRecordA =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
IpSecTransformCallRecord firstTransformRecordB =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
// Inject rekey IKE requests
mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeCreateReq));
mTunUtils.awaitResp(
IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeDeleteReq));
mTunUtils.awaitResp(
IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
// IKE has been rekeyed, reset message IDs
expectedReqMsgId = 0;
expectedRespMsgId = 0;
// Inject delete IKE request
mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq));
mTunUtils.awaitResp(
newIkeDeterministicInitSpi, expectedRespMsgId++, true /* expectedUseEncap */);
verifyDeleteIpSecTransformPair(
mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB);
mFirstChildSessionCallback.awaitOnClosed();
mIkeSessionCallback.awaitOnClosed();
}
@Test
public void testRekeyTransportModeChildSa() throws Exception {
final String ikeInitResp =
"46B8ECA1E0D72A18CECD871146CF83A121202220000000000000015022000030"
+ "0000002C010100040300000C0100000C800E0100030000080300000C03000008"
+ "0200000500000008040000022800008800020000C4904458957746BCF1C12972"
+ "1D4E19EB8A584F78DE673053396D167CE0F34552DBC69BA63FE7C673B4CF4A99"
+ "62481518EE985357876E8C47BAAA0DBE9C40AE47B12E52165874703586E8F786"
+ "045F72EEEB238C5D1823352BED44B71B3214609276ADC0B3D42DAC820168C4E2"
+ "660730DAAC92492403288805EBB9053F1AB060DA290000242D9364ACB93519FF"
+ "8F8B019BAA43A40D699F59714B327B8382216EF427ED52282900001C00004004"
+ "06D91438A0D6B734E152F76F5CC55A72A2E38A0A2900001C000040052EFF78B3"
+ "55B37F3CE75AFF26C721B050F892C0D6290000080000402E290000100000402F"
+ "00020003000400050000000800004014";
final String ikeAuthResp =
"46B8ECA1E0D72A18CECD871146CF83A12E20232000000001000000F0240000D4"
+ "A17BC258BA2714CF536663639DD5F665A60C75E93557CD5141990A8CEEDD2017"
+ "93F5B181C8569FBCD6C2A00198EC2B62D42BEFAC016B8B6BF6A7BC9CEDE3413A"
+ "6C495A6B8EC941864DC3E08F57D015EA6520C4B05884960B85478FCA53DA5F17"
+ "9628BB1097DA77461C71837207A9EB80720B3E6E661816EE4E14AC995B5E8441"
+ "A4C3F9097CC148142BA300076C94A23EC4ADE82B1DD2B121F7E9102860A8C3BF"
+ "58DDC207285A3176E924C44DE820322524E1AA438EFDFBA781B36084AED80846"
+ "3B77FCED9682B6E4E476408EF3F1037E";
final String rekeyChildCreateReq =
"46B8ECA1E0D72A18CECD871146CF83A12E202400000000000000015029000134"
+ "319D74B6B155B86942143CEC1D29D21F073F24B7BEDC9BFE0F0FDD8BDB5458C0"
+ "8DB93506E1A43DD0640FE7370C97F9B34FF4EC9B2DB7257A87B75632301FB68A"
+ "86B54871249534CA3D01C9BEB127B669F46470E1C8AAF72574C3CEEC15B901CF"
+ "5A0D6ADAE59C3CA64AC8C86689C860FAF9500E608DFE63F2DCD30510FD6FFCD5"
+ "A50838574132FD1D069BCACD4C7BAF45C9B1A7689FAD132E3F56DBCFAF905A8C"
+ "4145D4BA1B74A54762F8F43308D94DE05649C49D885121CE30681D51AC1E3E68"
+ "AB82F9A19B99579AFE257F32DBD1037814DA577379E4F42DEDAC84502E49C933"
+ "9EA83F6F5DB4401B660CB1681B023B8603D205DFDD1DE86AD8DE22B6B754F30D"
+ "05EAE81A709C2CEE81386133DC3DC7B5EF8F166E48E54A0722DD0C64F4D00638"
+ "40F272144C47F6ECED72A248180645DB";
final String rekeyChildDeleteReq =
"46B8ECA1E0D72A18CECD871146CF83A12E20250000000001000000502A000034"
+ "02D98DAF0432EBD991CA4F2D89C1E0EFABC6E91A3327A85D8914FB2F1485BE1B"
+ "8D3415D548F7CE0DC4224E7E9D0D3355";
final String deleteIkeReq =
"46B8ECA1E0D72A18CECD871146CF83A12E20250000000002000000502A000034"
+ "095041F4026B4634F04B0AB4F9349484F7BE9AEF03E3733EEE293330043B75D2"
+ "ABF5F965ED51127629585E1B1BBA787F";
// Open IKE Session
IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp);
// IKE INIT and IKE AUTH takes two exchanges. Local request message ID starts from 2
int expectedReqMsgId = 2;
int expectedRespMsgId = 0;
verifyIkeSessionSetupBlocking();
verifyChildSessionSetupBlocking(
mFirstChildSessionCallback,
Arrays.asList(TRANSPORT_MODE_INBOUND_TS),
Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS),
new ArrayList<LinkAddress>());
IpSecTransformCallRecord oldTransformRecordA =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
IpSecTransformCallRecord oldTransformRecordB =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
verifyCreateIpSecTransformPair(oldTransformRecordA, oldTransformRecordB);
// Inject rekey Child requests
mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildCreateReq));
mTunUtils.awaitResp(
IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildDeleteReq));
mTunUtils.awaitResp(
IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
// Verify IpSecTransforms are renewed
IpSecTransformCallRecord newTransformRecordA =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
IpSecTransformCallRecord newTransformRecordB =
mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
verifyCreateIpSecTransformPair(newTransformRecordA, newTransformRecordB);
verifyDeleteIpSecTransformPair(
mFirstChildSessionCallback, oldTransformRecordA, oldTransformRecordB);
// Inject delete IKE request
mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq));
mTunUtils.awaitResp(
IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
verifyDeleteIpSecTransformPair(
mFirstChildSessionCallback, newTransformRecordA, newTransformRecordB);
mFirstChildSessionCallback.awaitOnClosed();
mIkeSessionCallback.awaitOnClosed();
}
}

View File

@@ -1,598 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.IpSecManager;
import android.net.IpSecTransform;
import android.net.LinkAddress;
import android.net.Network;
import android.net.TestNetworkInterface;
import android.net.TestNetworkManager;
import android.net.annotations.PolicyDirection;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionConfiguration;
import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.TransportModeChildSessionParams;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.cts.IkeTunUtils.PortPair;
import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.compatibility.common.util.SystemUtil;
import com.android.net.module.util.ArrayTrackRecord;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Package private base class for testing IkeSessionParams and IKE exchanges.
*
* <p>Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use
* the test network
*
* <p>All IKE Sessions running in test mode will generate SPIs deterministically. That is to say
* each IKE Session will always generate the same IKE INIT SPI and test vectors are generated based
* on this deterministic IKE SPI. Each test will use different local and remote addresses to avoid
* the case that the next test try to allocate the same SPI before the previous test has released
* it, since SPI resources are not released in testing thread. Similarly, each test MUST use
* different Network instances to avoid sharing the same IkeSocket and hitting IKE SPI collision.
*/
@RunWith(AndroidJUnit4.class)
@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps")
abstract class IkeSessionTestBase extends IkeTestBase {
// Package-wide common expected results that will be shared by all IKE/Child SA creation tests
static final String EXPECTED_REMOTE_APP_VERSION_EMPTY = "";
static final byte[] EXPECTED_PROTOCOL_ERROR_DATA_NONE = new byte[0];
static final InetAddress EXPECTED_DNS_SERVERS_ONE =
InetAddresses.parseNumericAddress("8.8.8.8");
static final InetAddress EXPECTED_DNS_SERVERS_TWO =
InetAddresses.parseNumericAddress("8.8.4.4");
static final InetAddress EXPECTED_INTERNAL_ADDR =
InetAddresses.parseNumericAddress("198.51.100.10");
static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR =
new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN);
static final InetAddress EXPECTED_INTERNAL_ADDR_V6 =
InetAddresses.parseNumericAddress("2001:db8::2");
static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR_V6 =
new LinkAddress(EXPECTED_INTERNAL_ADDR_V6, IP6_PREFIX_LEN);
static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS =
new IkeTrafficSelector(
MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR);
static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS;
static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS_V6 =
new IkeTrafficSelector(
MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR_V6, EXPECTED_INTERNAL_ADDR_V6);
static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS_V6 = DEFAULT_V6_TS;
// This value is align with the test vectors hex that are generated in an IPv4 environment
static final IkeTrafficSelector TRANSPORT_MODE_OUTBOUND_TS =
new IkeTrafficSelector(
MIN_PORT,
MAX_PORT,
InetAddresses.parseNumericAddress("10.138.0.2"),
InetAddresses.parseNumericAddress("10.138.0.2"));
static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16);
// Static state to reduce setup/teardown
static Context sContext = InstrumentationRegistry.getContext();
static ConnectivityManager sCM =
(ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
static TestNetworkManager sTNM;
private static final int TIMEOUT_MS = 500;
// Constants to be used for providing different IP addresses for each tests
private static final byte IP_ADDR_LAST_BYTE_MAX = (byte) 100;
private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_LOCAL =
InetAddresses.parseNumericAddress("192.0.2.1").getAddress();
private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_REMOTE =
InetAddresses.parseNumericAddress("198.51.100.1").getAddress();
private static final byte[] NEXT_AVAILABLE_IP4_ADDR_LOCAL = INITIAL_AVAILABLE_IP4_ADDR_LOCAL;
private static final byte[] NEXT_AVAILABLE_IP4_ADDR_REMOTE = INITIAL_AVAILABLE_IP4_ADDR_REMOTE;
ParcelFileDescriptor mTunFd;
TestNetworkCallback mTunNetworkCallback;
Network mTunNetwork;
IkeTunUtils mTunUtils;
InetAddress mLocalAddress;
InetAddress mRemoteAddress;
Executor mUserCbExecutor;
TestIkeSessionCallback mIkeSessionCallback;
TestChildSessionCallback mFirstChildSessionCallback;
// This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass
// methods.
@BeforeClass
public static void setUpPermissionBeforeClass() throws Exception {
InstrumentationRegistry.getInstrumentation()
.getUiAutomation()
.adoptShellPermissionIdentity();
sTNM = sContext.getSystemService(TestNetworkManager.class);
}
// This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass
// methods.
@AfterClass
public static void tearDownPermissionAfterClass() throws Exception {
InstrumentationRegistry.getInstrumentation()
.getUiAutomation()
.dropShellPermissionIdentity();
}
@Before
public void setUp() throws Exception {
mLocalAddress = getNextAvailableIpv4AddressLocal();
mRemoteAddress = getNextAvailableIpv4AddressRemote();
setUpTestNetwork(mLocalAddress);
mUserCbExecutor = Executors.newSingleThreadExecutor();
mIkeSessionCallback = new TestIkeSessionCallback();
mFirstChildSessionCallback = new TestChildSessionCallback();
}
@After
public void tearDown() throws Exception {
tearDownTestNetwork();
}
void setUpTestNetwork(InetAddress localAddr) throws Exception {
int prefixLen = localAddr instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN;
TestNetworkInterface testIface =
sTNM.createTunInterface(new LinkAddress[] {new LinkAddress(localAddr, prefixLen)});
mTunFd = testIface.getFileDescriptor();
mTunNetworkCallback =
TestNetworkUtils.setupAndGetTestNetwork(
sCM, sTNM, testIface.getInterfaceName(), new Binder());
mTunNetwork = mTunNetworkCallback.getNetworkBlocking();
mTunUtils = new IkeTunUtils(mTunFd);
}
void tearDownTestNetwork() throws Exception {
sCM.unregisterNetworkCallback(mTunNetworkCallback);
sTNM.teardownTestNetwork(mTunNetwork);
mTunFd.close();
}
static void setAppOp(int appop, boolean allow) {
String opName = AppOpsManager.opToName(appop);
for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) {
String cmd =
String.format(
"appops set %s %s %s",
pkg, // Package name
opName, // Appop
(allow ? "allow" : "deny")); // Action
SystemUtil.runShellCommand(cmd);
}
}
Inet4Address getNextAvailableIpv4AddressLocal() throws Exception {
return (Inet4Address)
getNextAvailableAddress(
NEXT_AVAILABLE_IP4_ADDR_LOCAL,
INITIAL_AVAILABLE_IP4_ADDR_LOCAL,
false /* isIp6 */);
}
Inet4Address getNextAvailableIpv4AddressRemote() throws Exception {
return (Inet4Address)
getNextAvailableAddress(
NEXT_AVAILABLE_IP4_ADDR_REMOTE,
INITIAL_AVAILABLE_IP4_ADDR_REMOTE,
false /* isIp6 */);
}
InetAddress getNextAvailableAddress(
byte[] nextAddressBytes, byte[] initialAddressBytes, boolean isIp6) throws Exception {
int addressLen = isIp6 ? IP6_ADDRESS_LEN : IP4_ADDRESS_LEN;
synchronized (nextAddressBytes) {
if (nextAddressBytes[addressLen - 1] == IP_ADDR_LAST_BYTE_MAX) {
resetNextAvailableAddress(nextAddressBytes, initialAddressBytes);
}
InetAddress address = InetAddress.getByAddress(nextAddressBytes);
nextAddressBytes[addressLen - 1]++;
return address;
}
}
private void resetNextAvailableAddress(byte[] nextAddressBytes, byte[] initialAddressBytes) {
synchronized (nextAddressBytes) {
System.arraycopy(
nextAddressBytes, 0, initialAddressBytes, 0, initialAddressBytes.length);
}
}
TransportModeChildSessionParams buildTransportModeChildParamsWithTs(
IkeTrafficSelector inboundTs, IkeTrafficSelector outboundTs) {
return new TransportModeChildSessionParams.Builder()
.addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
.addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
.addInboundTrafficSelectors(inboundTs)
.addOutboundTrafficSelectors(outboundTs)
.build();
}
TransportModeChildSessionParams buildTransportModeChildParamsWithDefaultTs() {
return new TransportModeChildSessionParams.Builder()
.addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
.addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
.build();
}
TunnelModeChildSessionParams buildTunnelModeChildSessionParams() {
return new TunnelModeChildSessionParams.Builder()
.addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
.addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
.addInternalAddressRequest(AF_INET)
.addInternalAddressRequest(AF_INET6)
.build();
}
PortPair performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes)
throws Exception {
return performSetupIkeAndFirstChildBlocking(
ikeInitRespHex,
1 /* expectedAuthReqPktCnt */,
true /*expectedAuthUseEncap*/,
ikeAuthRespHexes);
}
PortPair performSetupIkeAndFirstChildBlocking(
String ikeInitRespHex, boolean expectedAuthUseEncap, String... ikeAuthRespHexes)
throws Exception {
return performSetupIkeAndFirstChildBlocking(
ikeInitRespHex,
1 /* expectedAuthReqPktCnt */,
expectedAuthUseEncap,
ikeAuthRespHexes);
}
PortPair performSetupIkeAndFirstChildBlocking(
String ikeInitRespHex,
int expectedAuthReqPktCnt,
boolean expectedAuthUseEncap,
String... ikeAuthRespHexes)
throws Exception {
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
0 /* expectedMsgId */,
false /* expectedUseEncap */,
ikeInitRespHex);
byte[] ikeAuthReqPkt =
mTunUtils
.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI,
1 /* expectedMsgId */,
expectedAuthUseEncap,
expectedAuthReqPktCnt,
ikeAuthRespHexes)
.get(0);
return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt);
}
void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception {
performCloseIkeBlocking(expectedMsgId, true /* expectedUseEncap*/, deleteIkeRespHex);
}
void performCloseIkeBlocking(
int expectedMsgId, boolean expectedUseEncap, String deleteIkeRespHex) throws Exception {
mTunUtils.awaitReqAndInjectResp(
IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId, expectedUseEncap, deleteIkeRespHex);
}
/** Testing callback that allows caller to block current thread until a method get called */
static class TestIkeSessionCallback implements IkeSessionCallback {
private CompletableFuture<IkeSessionConfiguration> mFutureIkeConfig =
new CompletableFuture<>();
private CompletableFuture<Boolean> mFutureOnClosedCall = new CompletableFuture<>();
private CompletableFuture<IkeException> mFutureOnClosedException =
new CompletableFuture<>();
private int mOnErrorExceptionsCount = 0;
private ArrayTrackRecord<IkeProtocolException> mOnErrorExceptionsTrackRecord =
new ArrayTrackRecord<>();
@Override
public void onOpened(@NonNull IkeSessionConfiguration sessionConfiguration) {
mFutureIkeConfig.complete(sessionConfiguration);
}
@Override
public void onClosed() {
mFutureOnClosedCall.complete(true /* unused */);
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
mFutureOnClosedException.complete(exception);
}
@Override
public void onError(@NonNull IkeProtocolException exception) {
mOnErrorExceptionsTrackRecord.add(exception);
}
public IkeSessionConfiguration awaitIkeConfig() throws Exception {
return mFutureIkeConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
public IkeException awaitOnClosedException() throws Exception {
return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
public IkeProtocolException awaitNextOnErrorException() {
return mOnErrorExceptionsTrackRecord.poll(
(long) TIMEOUT_MS,
mOnErrorExceptionsCount++,
(transform) -> {
return true;
});
}
public void awaitOnClosed() throws Exception {
mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
}
/** Testing callback that allows caller to block current thread until a method get called */
static class TestChildSessionCallback implements ChildSessionCallback {
private CompletableFuture<ChildSessionConfiguration> mFutureChildConfig =
new CompletableFuture<>();
private CompletableFuture<Boolean> mFutureOnClosedCall = new CompletableFuture<>();
private CompletableFuture<IkeException> mFutureOnClosedException =
new CompletableFuture<>();
private int mCreatedIpSecTransformCount = 0;
private int mDeletedIpSecTransformCount = 0;
private ArrayTrackRecord<IpSecTransformCallRecord> mCreatedIpSecTransformsTrackRecord =
new ArrayTrackRecord<>();
private ArrayTrackRecord<IpSecTransformCallRecord> mDeletedIpSecTransformsTrackRecord =
new ArrayTrackRecord<>();
@Override
public void onOpened(@NonNull ChildSessionConfiguration sessionConfiguration) {
mFutureChildConfig.complete(sessionConfiguration);
}
@Override
public void onClosed() {
mFutureOnClosedCall.complete(true /* unused */);
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
mFutureOnClosedException.complete(exception);
}
@Override
public void onIpSecTransformCreated(@NonNull IpSecTransform ipSecTransform, int direction) {
mCreatedIpSecTransformsTrackRecord.add(
new IpSecTransformCallRecord(ipSecTransform, direction));
}
@Override
public void onIpSecTransformDeleted(@NonNull IpSecTransform ipSecTransform, int direction) {
mDeletedIpSecTransformsTrackRecord.add(
new IpSecTransformCallRecord(ipSecTransform, direction));
}
public ChildSessionConfiguration awaitChildConfig() throws Exception {
return mFutureChildConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
public IkeException awaitOnClosedException() throws Exception {
return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
public IpSecTransformCallRecord awaitNextCreatedIpSecTransform() {
return mCreatedIpSecTransformsTrackRecord.poll(
(long) TIMEOUT_MS,
mCreatedIpSecTransformCount++,
(transform) -> {
return true;
});
}
public IpSecTransformCallRecord awaitNextDeletedIpSecTransform() {
return mDeletedIpSecTransformsTrackRecord.poll(
(long) TIMEOUT_MS,
mDeletedIpSecTransformCount++,
(transform) -> {
return true;
});
}
public void awaitOnClosed() throws Exception {
mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
}
/**
* This class represents a created or deleted IpSecTransfrom that is provided by
* ChildSessionCallback
*/
static class IpSecTransformCallRecord {
public final IpSecTransform ipSecTransform;
public final int direction;
IpSecTransformCallRecord(IpSecTransform ipSecTransform, @PolicyDirection int direction) {
this.ipSecTransform = ipSecTransform;
this.direction = direction;
}
@Override
public int hashCode() {
return Objects.hash(ipSecTransform, direction);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof IpSecTransformCallRecord)) return false;
IpSecTransformCallRecord record = (IpSecTransformCallRecord) o;
return ipSecTransform.equals(record.ipSecTransform) && direction == record.direction;
}
}
void verifyIkeSessionSetupBlocking() throws Exception {
IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig();
assertNotNull(ikeConfig);
assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion());
assertTrue(ikeConfig.getRemoteVendorIds().isEmpty());
assertTrue(ikeConfig.getPcscfServers().isEmpty());
assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION));
IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo();
assertNotNull(ikeConnectInfo);
assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress());
assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress());
assertEquals(mTunNetwork, ikeConnectInfo.getNetwork());
}
void verifyChildSessionSetupBlocking(
TestChildSessionCallback childCallback,
List<IkeTrafficSelector> expectedInboundTs,
List<IkeTrafficSelector> expectedOutboundTs,
List<LinkAddress> expectedInternalAddresses)
throws Exception {
verifyChildSessionSetupBlocking(
childCallback,
expectedInboundTs,
expectedOutboundTs,
expectedInternalAddresses,
new ArrayList<InetAddress>() /* expectedDnsServers */);
}
void verifyChildSessionSetupBlocking(
TestChildSessionCallback childCallback,
List<IkeTrafficSelector> expectedInboundTs,
List<IkeTrafficSelector> expectedOutboundTs,
List<LinkAddress> expectedInternalAddresses,
List<InetAddress> expectedDnsServers)
throws Exception {
ChildSessionConfiguration childConfig = childCallback.awaitChildConfig();
assertNotNull(childConfig);
assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors());
assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors());
assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses());
assertEquals(expectedDnsServers, childConfig.getInternalDnsServers());
assertTrue(childConfig.getInternalSubnets().isEmpty());
assertTrue(childConfig.getInternalDhcpServers().isEmpty());
}
void verifyCloseIkeAndChildBlocking(
IpSecTransformCallRecord expectedTransformRecordA,
IpSecTransformCallRecord expectedTransformRecordB)
throws Exception {
verifyDeleteIpSecTransformPair(
mFirstChildSessionCallback, expectedTransformRecordA, expectedTransformRecordB);
mFirstChildSessionCallback.awaitOnClosed();
mIkeSessionCallback.awaitOnClosed();
}
static void verifyCreateIpSecTransformPair(
IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) {
IpSecTransform transformA = transformRecordA.ipSecTransform;
IpSecTransform transformB = transformRecordB.ipSecTransform;
assertNotNull(transformA);
assertNotNull(transformB);
Set<Integer> expectedDirections = new HashSet<>();
expectedDirections.add(IpSecManager.DIRECTION_IN);
expectedDirections.add(IpSecManager.DIRECTION_OUT);
Set<Integer> resultDirections = new HashSet<>();
resultDirections.add(transformRecordA.direction);
resultDirections.add(transformRecordB.direction);
assertEquals(expectedDirections, resultDirections);
}
static void verifyDeleteIpSecTransformPair(
TestChildSessionCallback childCb,
IpSecTransformCallRecord expectedTransformRecordA,
IpSecTransformCallRecord expectedTransformRecordB) {
Set<IpSecTransformCallRecord> expectedTransforms = new HashSet<>();
expectedTransforms.add(expectedTransformRecordA);
expectedTransforms.add(expectedTransformRecordB);
Set<IpSecTransformCallRecord> resultTransforms = new HashSet<>();
resultTransforms.add(childCb.awaitNextDeletedIpSecTransform());
resultTransforms.add(childCb.awaitNextDeletedIpSecTransform());
assertEquals(expectedTransforms, resultTransforms);
}
/** Package private method to check if device has IPsec tunnels feature */
static boolean hasTunnelsFeature() {
return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS);
}
// TODO(b/148689509): Verify hostname based creation
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import android.net.InetAddresses;
import android.net.ipsec.ike.IkeTrafficSelector;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** Shared parameters and util methods for testing different components of IKE */
abstract class IkeTestBase {
static final int MIN_PORT = 0;
static final int MAX_PORT = 65535;
private static final int INBOUND_TS_START_PORT = MIN_PORT;
private static final int INBOUND_TS_END_PORT = 65520;
private static final int OUTBOUND_TS_START_PORT = 16;
private static final int OUTBOUND_TS_END_PORT = MAX_PORT;
static final int IP4_ADDRESS_LEN = 4;
static final int IP6_ADDRESS_LEN = 16;
static final int IP4_PREFIX_LEN = 32;
static final int IP6_PREFIX_LEN = 64;
static final byte[] IKE_PSK = "ikeAndroidPsk".getBytes();
static final String LOCAL_HOSTNAME = "client.test.ike.android.net";
static final String REMOTE_HOSTNAME = "server.test.ike.android.net";
static final String LOCAL_ASN1_DN_STRING = "CN=client.test.ike.android.net, O=Android, C=US";
static final String LOCAL_RFC822_NAME = "client.test.ike@example.com";
static final byte[] LOCAL_KEY_ID = "Local Key ID".getBytes();
static final int SUB_ID = 1;
static final byte[] EAP_IDENTITY = "test@android.net".getBytes();
static final String NETWORK_NAME = "android.net";
static final String EAP_MSCHAPV2_USERNAME = "mschapv2user";
static final String EAP_MSCHAPV2_PASSWORD = "password";
static final Inet4Address IPV4_ADDRESS_LOCAL =
(Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100"));
static final Inet4Address IPV4_ADDRESS_REMOTE =
(Inet4Address) (InetAddresses.parseNumericAddress("198.51.100.100"));
static final Inet6Address IPV6_ADDRESS_LOCAL =
(Inet6Address) (InetAddresses.parseNumericAddress("2001:db8::100"));
static final Inet6Address IPV6_ADDRESS_REMOTE =
(Inet6Address) (InetAddresses.parseNumericAddress("2001:db8:255::100"));
static final InetAddress PCSCF_IPV4_ADDRESS_1 = InetAddresses.parseNumericAddress("192.0.2.1");
static final InetAddress PCSCF_IPV4_ADDRESS_2 = InetAddresses.parseNumericAddress("192.0.2.2");
static final InetAddress PCSCF_IPV6_ADDRESS_1 =
InetAddresses.parseNumericAddress("2001:DB8::1");
static final InetAddress PCSCF_IPV6_ADDRESS_2 =
InetAddresses.parseNumericAddress("2001:DB8::2");
static final IkeTrafficSelector DEFAULT_V4_TS =
new IkeTrafficSelector(
MIN_PORT,
MAX_PORT,
InetAddresses.parseNumericAddress("0.0.0.0"),
InetAddresses.parseNumericAddress("255.255.255.255"));
static final IkeTrafficSelector DEFAULT_V6_TS =
new IkeTrafficSelector(
MIN_PORT,
MAX_PORT,
InetAddresses.parseNumericAddress("::"),
InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
static final IkeTrafficSelector INBOUND_V4_TS =
new IkeTrafficSelector(
INBOUND_TS_START_PORT,
INBOUND_TS_END_PORT,
InetAddresses.parseNumericAddress("192.0.2.10"),
InetAddresses.parseNumericAddress("192.0.2.20"));
static final IkeTrafficSelector OUTBOUND_V4_TS =
new IkeTrafficSelector(
OUTBOUND_TS_START_PORT,
OUTBOUND_TS_END_PORT,
InetAddresses.parseNumericAddress("198.51.100.0"),
InetAddresses.parseNumericAddress("198.51.100.255"));
static final IkeTrafficSelector INBOUND_V6_TS =
new IkeTrafficSelector(
INBOUND_TS_START_PORT,
INBOUND_TS_END_PORT,
InetAddresses.parseNumericAddress("2001:db8::10"),
InetAddresses.parseNumericAddress("2001:db8::128"));
static final IkeTrafficSelector OUTBOUND_V6_TS =
new IkeTrafficSelector(
OUTBOUND_TS_START_PORT,
OUTBOUND_TS_END_PORT,
InetAddresses.parseNumericAddress("2001:db8:255::64"),
InetAddresses.parseNumericAddress("2001:db8:255::255"));
// Verify Config requests in TunnelModeChildSessionParams and IkeSessionParams
<T> void verifyConfigRequestTypes(
Map<Class<? extends T>, Integer> expectedReqCntMap, List<? extends T> resultReqList) {
Map<Class<? extends T>, Integer> resultReqCntMap = new HashMap<>();
// Verify that every config request type in resultReqList is expected, and build
// resultReqCntMap at the same time
for (T resultReq : resultReqList) {
boolean isResultReqExpected = false;
for (Class<? extends T> expectedReqInterface : expectedReqCntMap.keySet()) {
if (expectedReqInterface.isInstance(resultReq)) {
isResultReqExpected = true;
resultReqCntMap.put(
expectedReqInterface,
resultReqCntMap.getOrDefault(expectedReqInterface, 0) + 1);
}
}
if (!isResultReqExpected) {
fail("Failed due to unexpected config request " + resultReq);
}
}
assertEquals(expectedReqCntMap, resultReqCntMap);
// TODO: Think of a neat way to validate both counts and values in this method. Probably can
// build Runnables as validators for count and values.
}
}

View File

@@ -1,377 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.net.ipsec.ike.cts.PacketUtils.BytePayload;
import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN;
import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN;
import static android.net.ipsec.ike.cts.PacketUtils.Ip4Header;
import static android.net.ipsec.ike.cts.PacketUtils.Ip6Header;
import static android.net.ipsec.ike.cts.PacketUtils.IpHeader;
import static android.net.ipsec.ike.cts.PacketUtils.Payload;
import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN;
import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader;
import static android.system.OsConstants.IPPROTO_UDP;
import static com.android.internal.util.HexDump.hexStringToByteArray;
import static org.junit.Assert.fail;
import android.os.ParcelFileDescriptor;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class IkeTunUtils extends TunUtils {
private static final int PORT_LEN = 2;
private static final int NON_ESP_MARKER_LEN = 4;
private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN];
private static final int IKE_INIT_SPI_OFFSET = 0;
private static final int IKE_FIRST_PAYLOAD_OFFSET = 16;
private static final int IKE_IS_RESP_BYTE_OFFSET = 19;
private static final int IKE_MSG_ID_OFFSET = 20;
private static final int IKE_HEADER_LEN = 28;
private static final int IKE_FRAG_NUM_OFFSET = 32;
private static final int IKE_PAYLOAD_TYPE_SKF = 53;
private static final int RSP_FLAG_MASK = 0x20;
public IkeTunUtils(ParcelFileDescriptor tunFd) {
super(tunFd);
}
/**
* Await the expected IKE request inject an IKE response (or a list of response fragments)
*
* @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without
* IP/UDP headers or NON ESP MARKER.
*/
public byte[] awaitReqAndInjectResp(
long expectedInitIkeSpi,
int expectedMsgId,
boolean expectedUseEncap,
String... ikeRespDataFragmentsHex)
throws Exception {
return awaitReqAndInjectResp(
expectedInitIkeSpi,
expectedMsgId,
expectedUseEncap,
1 /* expectedReqPktCnt */,
ikeRespDataFragmentsHex)
.get(0);
}
/**
* Await the expected IKE request (or the list of IKE request fragments) and inject an IKE
* response (or a list of response fragments)
*
* @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without
* IP/UDP headers or NON ESP MARKER.
*/
public List<byte[]> awaitReqAndInjectResp(
long expectedInitIkeSpi,
int expectedMsgId,
boolean expectedUseEncap,
int expectedReqPktCnt,
String... ikeRespDataFragmentsHex)
throws Exception {
List<byte[]> reqList = new ArrayList<>(expectedReqPktCnt);
if (expectedReqPktCnt == 1) {
// Expecting one complete IKE packet
byte[] req =
awaitIkePacket(
(pkt) -> {
return isExpectedIkePkt(
pkt,
expectedInitIkeSpi,
expectedMsgId,
false /* expectedResp */,
expectedUseEncap);
});
reqList.add(req);
} else {
// Expecting "expectedReqPktCnt" number of request fragments
for (int i = 0; i < expectedReqPktCnt; i++) {
// IKE Fragment number always starts from 1
int expectedFragNum = i + 1;
byte[] req =
awaitIkePacket(
(pkt) -> {
return isExpectedIkeFragPkt(
pkt,
expectedInitIkeSpi,
expectedMsgId,
false /* expectedResp */,
expectedUseEncap,
expectedFragNum);
});
reqList.add(req);
}
}
// All request fragments have the same addresses and ports
byte[] request = reqList.get(0);
// Build response header by flipping address and port
InetAddress srcAddr = getAddress(request, false /* shouldGetSource */);
InetAddress dstAddr = getAddress(request, true /* shouldGetSource */);
int srcPort = getPort(request, false /* shouldGetSource */);
int dstPort = getPort(request, true /* shouldGetSource */);
for (String resp : ikeRespDataFragmentsHex) {
byte[] response =
buildIkePacket(
srcAddr,
dstAddr,
srcPort,
dstPort,
expectedUseEncap,
hexStringToByteArray(resp));
injectPacket(response);
}
return reqList;
}
/** Await the expected IKE response */
public byte[] awaitResp(long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap)
throws Exception {
return awaitIkePacket(
(pkt) -> {
return isExpectedIkePkt(
pkt,
expectedInitIkeSpi,
expectedMsgId,
true /* expectedResp*/,
expectedUseEncap);
});
}
private byte[] awaitIkePacket(Predicate<byte[]> pktVerifier) throws Exception {
long endTime = System.currentTimeMillis() + TIMEOUT;
int startIndex = 0;
synchronized (mPackets) {
while (System.currentTimeMillis() < endTime) {
byte[] ikePkt = getFirstMatchingPacket(pktVerifier, startIndex);
if (ikePkt != null) {
return ikePkt; // We've found the packet we're looking for.
}
startIndex = mPackets.size();
// Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout
long waitTimeout = endTime - System.currentTimeMillis();
if (waitTimeout > 0) {
mPackets.wait(waitTimeout);
}
}
fail("No matching packet found");
}
throw new IllegalStateException(
"Hit an impossible case where fail() didn't throw an exception");
}
private static boolean isExpectedIkePkt(
byte[] pkt,
long expectedInitIkeSpi,
int expectedMsgId,
boolean expectedResp,
boolean expectedUseEncap) {
int ipProtocolOffset = isIpv6(pkt) ? IP6_PROTO_OFFSET : IP4_PROTO_OFFSET;
int ikeOffset = getIkeOffset(pkt, expectedUseEncap);
return pkt[ipProtocolOffset] == IPPROTO_UDP
&& expectedUseEncap == hasNonEspMarker(pkt)
&& isExpectedSpiAndMsgId(
pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp);
}
private static boolean isExpectedIkeFragPkt(
byte[] pkt,
long expectedInitIkeSpi,
int expectedMsgId,
boolean expectedResp,
boolean expectedUseEncap,
int expectedFragNum) {
return isExpectedIkePkt(
pkt, expectedInitIkeSpi, expectedMsgId, expectedResp, expectedUseEncap)
&& isExpectedFragNum(pkt, getIkeOffset(pkt, expectedUseEncap), expectedFragNum);
}
private static int getIkeOffset(byte[] pkt, boolean useEncap) {
if (isIpv6(pkt)) {
// IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap.
return IP6_HDRLEN + UDP_HDRLEN;
} else {
// Use default IPv4 header length (assuming no options)
int ikeOffset = IP4_HDRLEN + UDP_HDRLEN;
return useEncap ? ikeOffset + NON_ESP_MARKER_LEN : ikeOffset;
}
}
private static boolean hasNonEspMarker(byte[] pkt) {
ByteBuffer buffer = ByteBuffer.wrap(pkt);
int ikeOffset = IP4_HDRLEN + UDP_HDRLEN;
if (buffer.remaining() < ikeOffset) return false;
buffer.get(new byte[ikeOffset]); // Skip IP and UDP header
byte[] nonEspMarker = new byte[NON_ESP_MARKER_LEN];
if (buffer.remaining() < NON_ESP_MARKER_LEN) return false;
buffer.get(nonEspMarker);
return Arrays.equals(NON_ESP_MARKER, nonEspMarker);
}
private static boolean isExpectedSpiAndMsgId(
byte[] pkt,
int ikeOffset,
long expectedInitIkeSpi,
int expectedMsgId,
boolean expectedResp) {
if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false;
ByteBuffer buffer = ByteBuffer.wrap(pkt);
buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER)
buffer.mark(); // Mark this position so that later we can reset back here
// Check SPI
buffer.get(new byte[IKE_INIT_SPI_OFFSET]);
long initSpi = buffer.getLong();
if (expectedInitIkeSpi != initSpi) {
return false;
}
// Check direction
buffer.reset();
buffer.get(new byte[IKE_IS_RESP_BYTE_OFFSET]);
byte flagsByte = buffer.get();
boolean isResp = ((flagsByte & RSP_FLAG_MASK) != 0);
if (expectedResp != isResp) {
return false;
}
// Check message ID
buffer.reset();
buffer.get(new byte[IKE_MSG_ID_OFFSET]);
// Both the expected message ID and the packet's msgId are signed integers, so directly
// compare them.
int msgId = buffer.getInt();
if (expectedMsgId != msgId) {
return false;
}
return true;
}
private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) {
ByteBuffer buffer = ByteBuffer.wrap(pkt);
buffer.get(new byte[ikeOffset]);
buffer.mark(); // Mark this position so that later we can reset back here
// Check if it is a fragment packet
buffer.get(new byte[IKE_FIRST_PAYLOAD_OFFSET]);
int firstPayload = Byte.toUnsignedInt(buffer.get());
if (firstPayload != IKE_PAYLOAD_TYPE_SKF) {
return false;
}
// Check fragment number
buffer.reset();
buffer.get(new byte[IKE_FRAG_NUM_OFFSET]);
int fragNum = Short.toUnsignedInt(buffer.getShort());
return expectedFragNum == fragNum;
}
public static class PortPair {
public final int srcPort;
public final int dstPort;
public PortPair(int sourcePort, int destinationPort) {
srcPort = sourcePort;
dstPort = destinationPort;
}
}
public static PortPair getSrcDestPortPair(byte[] outboundIkePkt) throws Exception {
return new PortPair(
getPort(outboundIkePkt, true /* shouldGetSource */),
getPort(outboundIkePkt, false /* shouldGetSource */));
}
private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception {
int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN;
int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET;
int ipOffset = shouldGetSource ? srcIpOffset : srcIpOffset + ipLen;
ByteBuffer buffer = ByteBuffer.wrap(pkt);
buffer.get(new byte[ipOffset]);
byte[] ipAddrBytes = new byte[ipLen];
buffer.get(ipAddrBytes);
return InetAddress.getByAddress(ipAddrBytes);
}
private static int getPort(byte[] pkt, boolean shouldGetSource) {
ByteBuffer buffer = ByteBuffer.wrap(pkt);
int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN;
int portOffset = shouldGetSource ? srcPortOffset : srcPortOffset + PORT_LEN;
buffer.get(new byte[portOffset]);
return Short.toUnsignedInt(buffer.getShort());
}
public static byte[] buildIkePacket(
InetAddress srcAddr,
InetAddress dstAddr,
int srcPort,
int dstPort,
boolean useEncap,
byte[] ikePacket)
throws Exception {
if (useEncap) {
ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER_LEN + ikePacket.length);
buffer.put(NON_ESP_MARKER);
buffer.put(ikePacket);
ikePacket = buffer.array();
}
UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(ikePacket));
IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt);
return ipPkt.getPacketBytes();
}
private static IpHeader getIpHeader(
int protocol, InetAddress src, InetAddress dst, Payload payload) {
if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) {
throw new IllegalArgumentException("Invalid src/dst address combination");
}
if (src instanceof Inet6Address) {
return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload);
} else {
return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload);
}
}
}

View File

@@ -1,467 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.system.OsConstants.IPPROTO_IPV6;
import static android.system.OsConstants.IPPROTO_UDP;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* This code is a exact copy of {@link PacketUtils} in
* cts/tests/tests/net/src/android/net/cts/PacketUtils.java.
*
* <p>TODO(b/148689509): Statically include the PacketUtils source file instead of copying it.
*/
public class PacketUtils {
private static final String TAG = PacketUtils.class.getSimpleName();
private static final int DATA_BUFFER_LEN = 4096;
static final int IP4_HDRLEN = 20;
static final int IP6_HDRLEN = 40;
static final int UDP_HDRLEN = 8;
static final int TCP_HDRLEN = 20;
static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12;
// Not defined in OsConstants
static final int IPPROTO_IPV4 = 4;
static final int IPPROTO_ESP = 50;
// Encryption parameters
static final int AES_GCM_IV_LEN = 8;
static final int AES_CBC_IV_LEN = 16;
static final int AES_GCM_BLK_SIZE = 4;
static final int AES_CBC_BLK_SIZE = 16;
// Encryption algorithms
static final String AES = "AES";
static final String AES_CBC = "AES/CBC/NoPadding";
static final String HMAC_SHA_256 = "HmacSHA256";
public interface Payload {
byte[] getPacketBytes(IpHeader header) throws Exception;
void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception;
short length();
int getProtocolId();
}
public abstract static class IpHeader {
public final byte proto;
public final InetAddress srcAddr;
public final InetAddress dstAddr;
public final Payload payload;
public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) {
this.proto = (byte) proto;
this.srcAddr = src;
this.dstAddr = dst;
this.payload = payload;
}
public abstract byte[] getPacketBytes() throws Exception;
public abstract int getProtocolId();
}
public static class Ip4Header extends IpHeader {
private short checksum;
public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) {
super(proto, src, dst, payload);
}
public byte[] getPacketBytes() throws Exception {
ByteBuffer resultBuffer = buildHeader();
payload.addPacketBytes(this, resultBuffer);
return getByteArrayFromBuffer(resultBuffer);
}
public ByteBuffer buildHeader() {
ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
// Version, IHL
bb.put((byte) (0x45));
// DCSP, ECN
bb.put((byte) 0);
// Total Length
bb.putShort((short) (IP4_HDRLEN + payload.length()));
// Empty for Identification, Flags and Fragment Offset
bb.putShort((short) 0);
bb.put((byte) 0x40);
bb.put((byte) 0x00);
// TTL
bb.put((byte) 64);
// Protocol
bb.put(proto);
// Header Checksum
final int ipChecksumOffset = bb.position();
bb.putShort((short) 0);
// Src/Dst addresses
bb.put(srcAddr.getAddress());
bb.put(dstAddr.getAddress());
bb.putShort(ipChecksumOffset, calculateChecksum(bb));
return bb;
}
private short calculateChecksum(ByteBuffer bb) {
int checksum = 0;
// Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit
// aligned, so no special cases needed for unaligned values.
ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer();
while (shortBuffer.hasRemaining()) {
short val = shortBuffer.get();
// Wrap as needed
checksum = addAndWrapForChecksum(checksum, val);
}
return onesComplement(checksum);
}
public int getProtocolId() {
return IPPROTO_IPV4;
}
}
public static class Ip6Header extends IpHeader {
public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) {
super(nextHeader, src, dst, payload);
}
public byte[] getPacketBytes() throws Exception {
ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
// Version | Traffic Class (First 4 bits)
bb.put((byte) 0x60);
// Traffic class (Last 4 bits), Flow Label
bb.put((byte) 0);
bb.put((byte) 0);
bb.put((byte) 0);
// Payload Length
bb.putShort((short) payload.length());
// Next Header
bb.put(proto);
// Hop Limit
bb.put((byte) 64);
// Src/Dst addresses
bb.put(srcAddr.getAddress());
bb.put(dstAddr.getAddress());
// Payload
payload.addPacketBytes(this, bb);
return getByteArrayFromBuffer(bb);
}
public int getProtocolId() {
return IPPROTO_IPV6;
}
}
public static class BytePayload implements Payload {
public final byte[] payload;
public BytePayload(byte[] payload) {
this.payload = payload;
}
public int getProtocolId() {
return -1;
}
public byte[] getPacketBytes(IpHeader header) {
ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
addPacketBytes(header, bb);
return getByteArrayFromBuffer(bb);
}
public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) {
resultBuffer.put(payload);
}
public short length() {
return (short) payload.length;
}
}
public static class UdpHeader implements Payload {
public final short srcPort;
public final short dstPort;
public final Payload payload;
public UdpHeader(int srcPort, int dstPort, Payload payload) {
this.srcPort = (short) srcPort;
this.dstPort = (short) dstPort;
this.payload = payload;
}
public int getProtocolId() {
return IPPROTO_UDP;
}
public short length() {
return (short) (payload.length() + 8);
}
public byte[] getPacketBytes(IpHeader header) throws Exception {
ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
addPacketBytes(header, bb);
return getByteArrayFromBuffer(bb);
}
public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception {
// Source, Destination port
resultBuffer.putShort(srcPort);
resultBuffer.putShort(dstPort);
// Payload Length
resultBuffer.putShort(length());
// Get payload bytes for checksum + payload
ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
payload.addPacketBytes(header, payloadBuffer);
byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer);
// Checksum
resultBuffer.putShort(calculateChecksum(header, payloadBytes));
// Payload
resultBuffer.put(payloadBytes);
}
private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception {
int newChecksum = 0;
ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer();
ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer();
while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) {
short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get();
// Wrap as needed
newChecksum = addAndWrapForChecksum(newChecksum, val);
}
// Add pseudo-header values. Proto is 0-padded, so just use the byte.
newChecksum = addAndWrapForChecksum(newChecksum, header.proto);
newChecksum = addAndWrapForChecksum(newChecksum, length());
newChecksum = addAndWrapForChecksum(newChecksum, srcPort);
newChecksum = addAndWrapForChecksum(newChecksum, dstPort);
newChecksum = addAndWrapForChecksum(newChecksum, length());
ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer();
while (payloadShortBuffer.hasRemaining()) {
newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get());
}
if (payload.length() % 2 != 0) {
newChecksum =
addAndWrapForChecksum(
newChecksum, (payloadBytes[payloadBytes.length - 1] << 8));
}
return onesComplement(newChecksum);
}
}
public static class EspHeader implements Payload {
public final int nextHeader;
public final int spi;
public final int seqNum;
public final byte[] key;
public final byte[] payload;
/**
* Generic constructor for ESP headers.
*
* <p>For Tunnel mode, payload will be a full IP header + attached payloads
*
* <p>For Transport mode, payload will be only the attached payloads, but with the checksum
* calculated using the pre-encryption IP header
*/
public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) {
this.nextHeader = nextHeader;
this.spi = spi;
this.seqNum = seqNum;
this.key = key;
this.payload = payload;
}
public int getProtocolId() {
return IPPROTO_ESP;
}
public short length() {
// ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len)
return (short)
calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128);
}
public byte[] getPacketBytes(IpHeader header) throws Exception {
ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
addPacketBytes(header, bb);
return getByteArrayFromBuffer(bb);
}
public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception {
ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
espPayloadBuffer.putInt(spi);
espPayloadBuffer.putInt(seqNum);
espPayloadBuffer.put(getCiphertext(key));
espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16);
resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer));
}
private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException {
Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256);
SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256);
sha256HMAC.init(authKey);
return sha256HMAC.doFinal(authenticatedSection);
}
/**
* Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks
*
* <p>The ciphertext does NOT include the SPI/Sequence numbers, or the ICV.
*/
private byte[] getCiphertext(byte[] key) throws GeneralSecurityException {
int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE);
ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen);
paddedPayload.put(payload);
// Add padding - consecutive integers from 0x01
int pad = 1;
while (paddedPayload.position() < paddedPayload.limit()) {
paddedPayload.put((byte) pad++);
}
paddedPayload.position(paddedPayload.limit() - 2);
paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length
paddedPayload.put((byte) nextHeader);
// Generate Initialization Vector
byte[] iv = new byte[AES_CBC_IV_LEN];
new SecureRandom().nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES);
// Encrypt payload
Cipher cipher = Cipher.getInstance(AES_CBC);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload));
// Build ciphertext
ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length);
cipherText.put(iv);
cipherText.put(encrypted);
return getByteArrayFromBuffer(cipherText);
}
}
private static int addAndWrapForChecksum(int currentChecksum, int value) {
currentChecksum += value & 0x0000ffff;
// Wrap anything beyond the first 16 bits, and add to lower order bits
return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff);
}
private static short onesComplement(int val) {
val = (val >>> 16) + (val & 0xffff);
if (val == 0) return 0;
return (short) ((~val) & 0xffff);
}
public static int calculateEspPacketSize(
int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) {
final int ESP_HDRLEN = 4 + 4; // SPI + Seq#
final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length
payloadLen += cryptIvLength; // Initialization Vector
// Align to block size of encryption algorithm
payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize);
return payloadLen + ESP_HDRLEN + ICV_LEN;
}
private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) {
payloadLen += 2; // ESP trailer
// Align to block size of encryption algorithm
return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize);
}
private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) {
return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize;
}
private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) {
return Arrays.copyOfRange(buffer.array(), 0, buffer.position());
}
/*
* Debug printing
*/
private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(hexArray[b >>> 4]);
sb.append(hexArray[b & 0x0F]);
sb.append(' ');
}
return sb.toString();
}
}

View File

@@ -1,256 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP;
import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
import static android.net.ipsec.ike.SaProposal.DH_GROUP_NONE;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE;
import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128;
import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192;
import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED;
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256;
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384;
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.IkeSaProposal;
import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class SaProposalTest {
private static final List<Pair<Integer, Integer>> NORMAL_MODE_CIPHERS = new ArrayList<>();
private static final List<Pair<Integer, Integer>> COMBINED_MODE_CIPHERS = new ArrayList<>();
private static final List<Integer> INTEGRITY_ALGOS = new ArrayList<>();
private static final List<Integer> DH_GROUPS = new ArrayList<>();
private static final List<Integer> DH_GROUPS_WITH_NONE = new ArrayList<>();
private static final List<Integer> PRFS = new ArrayList<>();
static {
NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED));
NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128));
NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192));
NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256));
COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128));
COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192));
COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256));
INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_AES_XCBC_96);
INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
DH_GROUPS.add(DH_GROUP_1024_BIT_MODP);
DH_GROUPS.add(DH_GROUP_2048_BIT_MODP);
DH_GROUPS_WITH_NONE.add(DH_GROUP_NONE);
DH_GROUPS_WITH_NONE.addAll(DH_GROUPS);
PRFS.add(PSEUDORANDOM_FUNCTION_HMAC_SHA1);
PRFS.add(PSEUDORANDOM_FUNCTION_AES128_XCBC);
PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_256);
PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_384);
PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_512);
}
// Package private
static IkeSaProposal buildIkeSaProposalWithNormalModeCipher() {
return buildIkeSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, PRFS, DH_GROUPS);
}
// Package private
static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher() {
return buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
}
private static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher(
boolean hasIntegrityNone) {
List<Integer> integerAlgos = new ArrayList<>();
if (hasIntegrityNone) {
integerAlgos.add(INTEGRITY_ALGORITHM_NONE);
}
return buildIkeSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, PRFS, DH_GROUPS);
}
private static IkeSaProposal buildIkeSaProposal(
List<Pair<Integer, Integer>> ciphers,
List<Integer> integrityAlgos,
List<Integer> prfs,
List<Integer> dhGroups) {
IkeSaProposal.Builder builder = new IkeSaProposal.Builder();
for (Pair<Integer, Integer> pair : ciphers) {
builder.addEncryptionAlgorithm(pair.first, pair.second);
}
for (int algo : integrityAlgos) {
builder.addIntegrityAlgorithm(algo);
}
for (int algo : prfs) {
builder.addPseudorandomFunction(algo);
}
for (int algo : dhGroups) {
builder.addDhGroup(algo);
}
return builder.build();
}
// Package private
static ChildSaProposal buildChildSaProposalWithNormalModeCipher() {
return buildChildSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, DH_GROUPS_WITH_NONE);
}
// Package private
static ChildSaProposal buildChildSaProposalWithCombinedModeCipher() {
return buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
}
private static ChildSaProposal buildChildSaProposalWithCombinedModeCipher(
boolean hasIntegrityNone) {
List<Integer> integerAlgos = new ArrayList<>();
if (hasIntegrityNone) {
integerAlgos.add(INTEGRITY_ALGORITHM_NONE);
}
return buildChildSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, DH_GROUPS_WITH_NONE);
}
private static ChildSaProposal buildChildSaProposal(
List<Pair<Integer, Integer>> ciphers,
List<Integer> integrityAlgos,
List<Integer> dhGroups) {
ChildSaProposal.Builder builder = new ChildSaProposal.Builder();
for (Pair<Integer, Integer> pair : ciphers) {
builder.addEncryptionAlgorithm(pair.first, pair.second);
}
for (int algo : integrityAlgos) {
builder.addIntegrityAlgorithm(algo);
}
for (int algo : dhGroups) {
builder.addDhGroup(algo);
}
return builder.build();
}
// Package private
static ChildSaProposal buildChildSaProposalWithOnlyCiphers() {
return buildChildSaProposal(
COMBINED_MODE_CIPHERS, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
}
@Test
public void testBuildIkeSaProposalWithNormalModeCipher() {
IkeSaProposal saProposal = buildIkeSaProposalWithNormalModeCipher();
assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms());
assertEquals(PRFS, saProposal.getPseudorandomFunctions());
assertEquals(DH_GROUPS, saProposal.getDhGroups());
}
@Test
public void testBuildIkeSaProposalWithCombinedModeCipher() {
IkeSaProposal saProposal =
buildIkeSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */);
assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertEquals(PRFS, saProposal.getPseudorandomFunctions());
assertEquals(DH_GROUPS, saProposal.getDhGroups());
assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
}
@Test
public void testBuildIkeSaProposalWithCombinedModeCipherAndIntegrityNone() {
IkeSaProposal saProposal =
buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertEquals(PRFS, saProposal.getPseudorandomFunctions());
assertEquals(DH_GROUPS, saProposal.getDhGroups());
assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms());
}
@Test
public void testBuildChildSaProposalWithNormalModeCipher() {
ChildSaProposal saProposal = buildChildSaProposalWithNormalModeCipher();
assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms());
assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
}
@Test
public void testBuildChildProposalWithCombinedModeCipher() {
ChildSaProposal saProposal =
buildChildSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */);
assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
}
@Test
public void testBuildChildProposalWithCombinedModeCipherAndIntegrityNone() {
ChildSaProposal saProposal =
buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms());
assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
}
@Test
public void testBuildChildSaProposalWithOnlyCiphers() {
ChildSaProposal saProposal = buildChildSaProposalWithOnlyCiphers();
assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
assertTrue(saProposal.getDhGroups().isEmpty());
}
// TODO(b/148689509): Test throwing exception when algorithm combination is invalid
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkRequest;
import android.net.TestNetworkManager;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
// TODO(b/148689509): Share this class with net CTS test (e.g. IpSecManagerTunnelTest)
public class TestNetworkUtils {
private static final int TIMEOUT_MS = 500;
/** Callback to receive requested test network. */
public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
private final CompletableFuture<Network> futureNetwork = new CompletableFuture<>();
@Override
public void onAvailable(Network network) {
futureNetwork.complete(network);
}
public Network getNetworkBlocking() throws Exception {
return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
}
/**
* Set up test network.
*
* <p>Caller MUST have MANAGE_TEST_NETWORKS permission to use this method.
*
* @param connMgr ConnectivityManager to request network.
* @param testNetworkMgr TestNetworkManager to set up test network.
* @param ifname the name of the interface to be used for the Network LinkProperties.
* @param binder a binder object guarding the lifecycle of this test network.
* @return TestNetworkCallback to retrieve the test network.
* @throws RemoteException if test network setup failed.
* @see android.net.TestNetworkManager
*/
public static TestNetworkCallback setupAndGetTestNetwork(
ConnectivityManager connMgr,
TestNetworkManager testNetworkMgr,
String ifname,
IBinder binder)
throws RemoteException {
NetworkRequest nr =
new NetworkRequest.Builder()
.addTransportType(TRANSPORT_TEST)
.removeCapability(NET_CAPABILITY_TRUSTED)
.removeCapability(NET_CAPABILITY_NOT_VPN)
.setNetworkSpecifier(ifname)
.build();
TestNetworkCallback cb = new TestNetworkCallback();
connMgr.requestNetwork(nr, cb);
// Setup the test network after network request is filed to prevent Network from being
// reaped due to no requests matching it.
testNetworkMgr.setupTestNetwork(ifname, binder);
return cb;
}
}

View File

@@ -1,264 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ipsec.ike.cts;
import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN;
import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN;
import static android.net.ipsec.ike.cts.PacketUtils.IPPROTO_ESP;
import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN;
import static android.system.OsConstants.IPPROTO_UDP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import android.os.ParcelFileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
/**
* This code is a exact copy of {@link TunUtils} in
* cts/tests/tests/net/src/android/net/cts/TunUtils.java, except the import path of PacketUtils is
* the path to the copy of PacktUtils.
*
* <p>TODO(b/148689509): Statically include the TunUtils source file instead of copying it.
*/
public class TunUtils {
private static final String TAG = TunUtils.class.getSimpleName();
private static final int DATA_BUFFER_LEN = 4096;
static final int TIMEOUT = 500;
static final int IP4_PROTO_OFFSET = 9;
static final int IP6_PROTO_OFFSET = 6;
static final int IP4_ADDR_OFFSET = 12;
static final int IP4_ADDR_LEN = 4;
static final int IP6_ADDR_OFFSET = 8;
static final int IP6_ADDR_LEN = 16;
final List<byte[]> mPackets = new ArrayList<>();
private final ParcelFileDescriptor mTunFd;
private final Thread mReaderThread;
public TunUtils(ParcelFileDescriptor tunFd) {
mTunFd = tunFd;
// Start background reader thread
mReaderThread =
new Thread(
() -> {
try {
// Loop will exit and thread will quit when tunFd is closed.
// Receiving either EOF or an exception will exit this reader loop.
// FileInputStream in uninterruptable, so there's no good way to
// ensure that this thread shuts down except upon FD closure.
while (true) {
byte[] intercepted = receiveFromTun();
if (intercepted == null) {
// Exit once we've hit EOF
return;
} else if (intercepted.length > 0) {
// Only save packet if we've received any bytes.
synchronized (mPackets) {
mPackets.add(intercepted);
mPackets.notifyAll();
}
}
}
} catch (IOException ignored) {
// Simply exit this reader thread
return;
}
});
mReaderThread.start();
}
private byte[] receiveFromTun() throws IOException {
FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor());
byte[] inBytes = new byte[DATA_BUFFER_LEN];
int bytesRead = in.read(inBytes);
if (bytesRead < 0) {
return null; // return null for EOF
} else if (bytesRead >= DATA_BUFFER_LEN) {
throw new IllegalStateException("Too big packet. Fragmentation unsupported");
}
return Arrays.copyOf(inBytes, bytesRead);
}
byte[] getFirstMatchingPacket(Predicate<byte[]> verifier, int startIndex) {
synchronized (mPackets) {
for (int i = startIndex; i < mPackets.size(); i++) {
byte[] pkt = mPackets.get(i);
if (verifier.test(pkt)) {
return pkt;
}
}
}
return null;
}
/**
* Checks if the specified bytes were ever sent in plaintext.
*
* <p>Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like
*
* @param plaintext the plaintext bytes to check for
* @param startIndex the index in the list to check for
*/
public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) {
Predicate<byte[]> verifier =
(pkt) -> {
return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext))
!= -1;
};
return getFirstMatchingPacket(verifier, startIndex) != null;
}
public byte[] getEspPacket(int spi, boolean encap, int startIndex) {
return getFirstMatchingPacket(
(pkt) -> {
return isEsp(pkt, spi, encap);
},
startIndex);
}
public byte[] awaitEspPacketNoPlaintext(
int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception {
long endTime = System.currentTimeMillis() + TIMEOUT;
int startIndex = 0;
synchronized (mPackets) {
while (System.currentTimeMillis() < endTime) {
byte[] espPkt = getEspPacket(spi, useEncap, startIndex);
if (espPkt != null) {
// Validate packet size
assertEquals(expectedPacketSize, espPkt.length);
// Always check plaintext from start
assertFalse(hasPlaintextPacket(plaintext, 0));
return espPkt; // We've found the packet we're looking for.
}
startIndex = mPackets.size();
// Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout
long waitTimeout = endTime - System.currentTimeMillis();
if (waitTimeout > 0) {
mPackets.wait(waitTimeout);
}
}
fail("No such ESP packet found with SPI " + spi);
}
return null;
}
private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) {
// Check SPI byte by byte.
return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff)
&& pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff)
&& pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff)
&& pkt[espOffset + 3] == (byte) (spi & 0xff);
}
private static boolean isEsp(byte[] pkt, int spi, boolean encap) {
if (isIpv6(pkt)) {
// IPv6 UDP encap not supported by kernels; assume non-encap.
return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi);
} else {
// Use default IPv4 header length (assuming no options)
if (encap) {
return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP
&& isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi);
} else {
return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi);
}
}
}
static boolean isIpv6(byte[] pkt) {
// First nibble shows IP version. 0x60 for IPv6
return (pkt[0] & (byte) 0xF0) == (byte) 0x60;
}
private static byte[] getReflectedPacket(byte[] pkt) {
byte[] reflected = Arrays.copyOf(pkt, pkt.length);
if (isIpv6(pkt)) {
// Set reflected packet's dst to that of the original's src
System.arraycopy(
pkt, // src
IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset
reflected, // dst
IP6_ADDR_OFFSET, // dst offset
IP6_ADDR_LEN); // len
// Set reflected packet's src IP to that of the original's dst IP
System.arraycopy(
pkt, // src
IP6_ADDR_OFFSET, // src offset
reflected, // dst
IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset
IP6_ADDR_LEN); // len
} else {
// Set reflected packet's dst to that of the original's src
System.arraycopy(
pkt, // src
IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset
reflected, // dst
IP4_ADDR_OFFSET, // dst offset
IP4_ADDR_LEN); // len
// Set reflected packet's src IP to that of the original's dst IP
System.arraycopy(
pkt, // src
IP4_ADDR_OFFSET, // src offset
reflected, // dst
IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset
IP4_ADDR_LEN); // len
}
return reflected;
}
/** Takes all captured packets, flips the src/dst, and re-injects them. */
public void reflectPackets() throws IOException {
synchronized (mPackets) {
for (byte[] pkt : mPackets) {
injectPacket(getReflectedPacket(pkt));
}
}
}
public void injectPacket(byte[] pkt) throws IOException {
FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor());
out.write(pkt);
out.flush();
}
/** Resets the intercepted packets. */
public void reset() throws IOException {
synchronized (mPackets) {
mPackets.clear();
}
}
}