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:
@@ -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",
|
||||
],
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -1,3 +0,0 @@
|
||||
lorenzo@google.com
|
||||
nharold@google.com
|
||||
satk@google.com
|
||||
@@ -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-----
|
||||
@@ -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-----
|
||||
@@ -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-----
|
||||
@@ -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-----
|
||||
@@ -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-----
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user