Snap for 6436225 from 99662c49a7 to rvc-release
Change-Id: Iadf40d09372a9e039fdd2394f630a0c7338d5072
This commit is contained in:
@@ -26,6 +26,7 @@ android_test {
|
||||
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
":ike-test-utils",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
|
||||
28
tests/cts/net/ipsec/assets/key/client-a-private-key.key
Normal file
28
tests/cts/net/ipsec/assets/key/client-a-private-key.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----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-----
|
||||
21
tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem
Normal file
21
tests/cts/net/ipsec/assets/pem/client-a-end-cert.pem
Normal file
@@ -0,0 +1,21 @@
|
||||
-----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-----
|
||||
@@ -0,0 +1,21 @@
|
||||
-----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-----
|
||||
@@ -0,0 +1,21 @@
|
||||
-----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-----
|
||||
20
tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem
Normal file
20
tests/cts/net/ipsec/assets/pem/server-a-self-signed-ca.pem
Normal file
@@ -0,0 +1,20 @@
|
||||
-----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-----
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* 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.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 IkeSessionParamsTestBase {
|
||||
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 {
|
||||
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");
|
||||
}
|
||||
|
||||
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(sTunNetwork)
|
||||
.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(sTunNetwork, 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(sTunNetwork)
|
||||
.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(sTunNetwork, 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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.Network;
|
||||
import android.net.TestNetworkInterface;
|
||||
import android.net.TestNetworkManager;
|
||||
import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.platform.test.annotations.AppModeFull;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps")
|
||||
abstract class IkeSessionParamsTestBase extends IkeTestBase {
|
||||
// Static state to reduce setup/teardown
|
||||
static ConnectivityManager sCM;
|
||||
static TestNetworkManager sTNM;
|
||||
static ParcelFileDescriptor sTunFd;
|
||||
static TestNetworkCallback sTunNetworkCallback;
|
||||
static Network sTunNetwork;
|
||||
|
||||
static Context sContext = InstrumentationRegistry.getContext();
|
||||
static IBinder sBinder = new Binder();
|
||||
|
||||
// This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass
|
||||
// methods.
|
||||
@BeforeClass
|
||||
public static void setUpTestNetworkBeforeClass() throws Exception {
|
||||
InstrumentationRegistry.getInstrumentation()
|
||||
.getUiAutomation()
|
||||
.adoptShellPermissionIdentity();
|
||||
sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE);
|
||||
|
||||
TestNetworkInterface testIface =
|
||||
sTNM.createTunInterface(
|
||||
new LinkAddress[] {new LinkAddress(IPV4_ADDRESS_LOCAL, IP4_PREFIX_LEN)});
|
||||
|
||||
sTunFd = testIface.getFileDescriptor();
|
||||
sTunNetworkCallback =
|
||||
TestNetworkUtils.setupAndGetTestNetwork(
|
||||
sCM, sTNM, testIface.getInterfaceName(), sBinder);
|
||||
sTunNetwork = sTunNetworkCallback.getNetworkBlocking();
|
||||
}
|
||||
|
||||
// This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass
|
||||
// methods.
|
||||
@AfterClass
|
||||
public static void tearDownTestNetworkAfterClass() throws Exception {
|
||||
sCM.unregisterNetworkCallback(sTunNetworkCallback);
|
||||
|
||||
sTNM.teardownTestNetwork(sTunNetwork);
|
||||
sTunFd.close();
|
||||
|
||||
InstrumentationRegistry.getInstrumentation()
|
||||
.getUiAutomation()
|
||||
.dropShellPermissionIdentity();
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ 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;
|
||||
@@ -40,6 +41,20 @@ abstract class IkeTestBase {
|
||||
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 = "username";
|
||||
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 =
|
||||
@@ -49,6 +64,13 @@ abstract class IkeTestBase {
|
||||
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,
|
||||
|
||||
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
264
tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java
Normal file
264
tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 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;
|
||||
private static final int TIMEOUT = 100;
|
||||
|
||||
private static final int IP4_PROTO_OFFSET = 9;
|
||||
private static final int IP6_PROTO_OFFSET = 6;
|
||||
|
||||
private static final int IP4_ADDR_OFFSET = 12;
|
||||
private static final int IP4_ADDR_LEN = 4;
|
||||
private static final int IP6_ADDR_OFFSET = 8;
|
||||
private static final int IP6_ADDR_LEN = 16;
|
||||
|
||||
private final ParcelFileDescriptor mTunFd;
|
||||
private final List<byte[]> mPackets = new ArrayList<>();
|
||||
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);
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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