blob: 646b9d9a4e3d75e6aff5f61c1b8e24450385864b [file] [log] [blame]
/*
* Copyright (C) 2019 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 com.android.internal.net.ipsec.ike;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.IpSecManager;
import android.net.IpSecManager.SecurityParameterIndex;
import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.IpSecTransform;
import android.net.ipsec.ike.SaProposal;
import com.android.internal.net.TestUtils;
import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IkeSecurityParameterIndex;
import com.android.internal.net.ipsec.ike.SaRecord.ChildSaRecord;
import com.android.internal.net.ipsec.ike.SaRecord.ChildSaRecordConfig;
import com.android.internal.net.ipsec.ike.SaRecord.IIpSecTransformHelper;
import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecordConfig;
import com.android.internal.net.ipsec.ike.SaRecord.IpSecTransformHelper;
import com.android.internal.net.ipsec.ike.SaRecord.SaRecordHelper;
import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
import com.android.internal.net.ipsec.ike.message.IkeMessage;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
import com.android.internal.net.ipsec.ike.testutils.MockIpSecTestUtils;
import com.android.server.IpSecService;
import libcore.net.InetAddressUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.net.Inet4Address;
@RunWith(JUnit4.class)
public final class SaRecordTest {
private static final Inet4Address LOCAL_ADDRESS =
(Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200"));
private static final Inet4Address REMOTE_ADDRESS =
(Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
private static final String PRF_KEY_HEX_STRING = "094787780EE466E2CB049FA327B43908BC57E485";
private static final String DATA_TO_SIGN_HEX_STRING = "010000000a50500d";
private static final String CALCULATED_MAC_HEX_STRING =
"D83B20CC6A0932B2A7CEF26E4020ABAAB64F0C6A";
private static final long IKE_INIT_SPI = 0x5F54BF6D8B48E6E1L;
private static final long IKE_RESP_SPI = 0x909232B3D1EDCB5CL;
private static final String IKE_NONCE_INIT_HEX_STRING =
"C39B7F368F4681B89FA9B7BE6465ABD7C5F68B6ED5D3B4C72CB4240EB5C46412";
private static final String IKE_NONCE_RESP_HEX_STRING =
"9756112CA539F5C25ABACC7EE92B73091942A9C06950F98848F1AF1694C4DDFF";
private static final String IKE_SHARED_DH_KEY_HEX_STRING =
"C14155DEA40056BD9C76FB4819687B7A397582F4CD5AFF4B"
+ "8F441C56E0C08C84234147A0BA249A555835A048E3CA2980"
+ "7D057A61DD26EEFAD9AF9C01497005E52858E29FB42EB849"
+ "6731DF96A11CCE1F51137A9A1B900FA81AEE7898E373D4E4"
+ "8B899BBECA091314ECD4B6E412EF4B0FEF798F54735F3180"
+ "7424A318287F20E8";
private static final String IKE_SKEYSEED_HEX_STRING =
"8C42F3B1F5F81C7BAAC5F33E9A4F01987B2F9657";
private static final String IKE_SK_D_HEX_STRING = "C86B56EFCF684DCC2877578AEF3137167FE0EBF6";
private static final String IKE_SK_AUTH_INIT_HEX_STRING =
"554FBF5A05B7F511E05A30CE23D874DB9EF55E51";
private static final String IKE_SK_AUTH_RESP_HEX_STRING =
"36D83420788337CA32ECAA46892C48808DCD58B1";
private static final String IKE_SK_ENCR_INIT_HEX_STRING = "5CBFD33F75796C0188C4A3A546AEC4A1";
private static final String IKE_SK_ENCR_RESP_HEX_STRING = "C33B35FCF29514CD9D8B4A695E1A816E";
private static final String IKE_SK_PRF_INIT_HEX_STRING =
"094787780EE466E2CB049FA327B43908BC57E485";
private static final String IKE_SK_PRF_RESP_HEX_STRING =
"A30E6B08BE56C0E6BFF4744143C75219299E1BEB";
private static final String IKE_KEY_MAT =
IKE_SK_D_HEX_STRING
+ IKE_SK_AUTH_INIT_HEX_STRING
+ IKE_SK_AUTH_RESP_HEX_STRING
+ IKE_SK_ENCR_INIT_HEX_STRING
+ IKE_SK_ENCR_RESP_HEX_STRING
+ IKE_SK_PRF_INIT_HEX_STRING
+ IKE_SK_PRF_RESP_HEX_STRING;
private static final int IKE_AUTH_ALGO_KEY_LEN = 20;
private static final int IKE_ENCR_ALGO_KEY_LEN = 16;
private static final int IKE_PRF_KEY_LEN = 20;
private static final int IKE_SK_D_KEY_LEN = IKE_PRF_KEY_LEN;
private static final int FIRST_CHILD_INIT_SPI = 0x2ad4c0a2;
private static final int FIRST_CHILD_RESP_SPI = 0xcae7019f;
private static final String FIRST_CHILD_ENCR_INIT_HEX_STRING =
"1B865CEA6E2C23973E8C5452ADC5CD7D";
private static final String FIRST_CHILD_ENCR_RESP_HEX_STRING =
"5E82FEDACC6DCB0756DDD7553907EBD1";
private static final String FIRST_CHILD_AUTH_INIT_HEX_STRING =
"A7A5A44F7EF4409657206C7DC52B7E692593B51E";
private static final String FIRST_CHILD_AUTH_RESP_HEX_STRING =
"CDE612189FD46DE870FAEC04F92B40B0BFDBD9E1";
private static final String FIRST_CHILD_KEY_MAT =
FIRST_CHILD_ENCR_INIT_HEX_STRING
+ FIRST_CHILD_AUTH_INIT_HEX_STRING
+ FIRST_CHILD_ENCR_RESP_HEX_STRING
+ FIRST_CHILD_AUTH_RESP_HEX_STRING;
private static final int FIRST_CHILD_AUTH_ALGO_KEY_LEN = 20;
private static final int FIRST_CHILD_ENCR_ALGO_KEY_LEN = 16;
private IkeMacPrf mIkeHmacSha1Prf;
private IkeMacIntegrity mHmacSha1IntegrityMac;
private IkeCipher mAesCbcCipher;
private LocalRequest mMockFutureRekeyIkeEvent;
private ChildLocalRequest mMockFutureRekeyChildEvent;
private SaRecordHelper mSaRecordHelper = new SaRecordHelper();
@Before
public void setUp() throws Exception {
mIkeHmacSha1Prf =
IkeMacPrf.create(
new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1),
IkeMessage.getSecurityProvider());
mHmacSha1IntegrityMac =
IkeMacIntegrity.create(
new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96),
IkeMessage.getSecurityProvider());
mAesCbcCipher =
IkeCipher.create(
new EncryptionTransform(
SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
SaProposal.KEY_LEN_AES_128),
IkeMessage.getSecurityProvider());
mMockFutureRekeyIkeEvent = mock(LocalRequest.class);
mMockFutureRekeyChildEvent = mock(ChildLocalRequest.class);
}
// Test generating keying material for making IKE SA.
@Test
public void testMakeIkeSaRecord() throws Exception {
byte[] sKeySeed = TestUtils.hexStringToByteArray(IKE_SKEYSEED_HEX_STRING);
byte[] nonceInit = TestUtils.hexStringToByteArray(IKE_NONCE_INIT_HEX_STRING);
byte[] nonceResp = TestUtils.hexStringToByteArray(IKE_NONCE_RESP_HEX_STRING);
IkeSecurityParameterIndex ikeInitSpi =
IkeSecurityParameterIndex.allocateSecurityParameterIndex(
LOCAL_ADDRESS, IKE_INIT_SPI);
IkeSecurityParameterIndex ikeRespSpi =
IkeSecurityParameterIndex.allocateSecurityParameterIndex(
REMOTE_ADDRESS, IKE_RESP_SPI);
IkeSaRecordConfig ikeSaRecordConfig =
new IkeSaRecordConfig(
ikeInitSpi,
ikeRespSpi,
mIkeHmacSha1Prf,
IKE_AUTH_ALGO_KEY_LEN,
IKE_ENCR_ALGO_KEY_LEN,
true /*isLocalInit*/,
mMockFutureRekeyIkeEvent);
int keyMaterialLen =
IKE_SK_D_KEY_LEN
+ IKE_AUTH_ALGO_KEY_LEN * 2
+ IKE_ENCR_ALGO_KEY_LEN * 2
+ IKE_PRF_KEY_LEN * 2;
IkeSaRecord ikeSaRecord =
mSaRecordHelper.makeIkeSaRecord(sKeySeed, nonceInit, nonceResp, ikeSaRecordConfig);
assertTrue(ikeSaRecord.isLocalInit);
assertEquals(IKE_INIT_SPI, ikeSaRecord.getInitiatorSpi());
assertEquals(IKE_RESP_SPI, ikeSaRecord.getResponderSpi());
assertArrayEquals(
TestUtils.hexStringToByteArray(IKE_SK_D_HEX_STRING), ikeSaRecord.getSkD());
assertArrayEquals(
TestUtils.hexStringToByteArray(IKE_SK_AUTH_INIT_HEX_STRING),
ikeSaRecord.getOutboundIntegrityKey());
assertArrayEquals(
TestUtils.hexStringToByteArray(IKE_SK_AUTH_RESP_HEX_STRING),
ikeSaRecord.getInboundIntegrityKey());
assertArrayEquals(
TestUtils.hexStringToByteArray(IKE_SK_ENCR_INIT_HEX_STRING),
ikeSaRecord.getOutboundEncryptionKey());
assertArrayEquals(
TestUtils.hexStringToByteArray(IKE_SK_ENCR_RESP_HEX_STRING),
ikeSaRecord.getInboundDecryptionKey());
assertArrayEquals(
TestUtils.hexStringToByteArray(IKE_SK_PRF_INIT_HEX_STRING), ikeSaRecord.getSkPi());
assertArrayEquals(
TestUtils.hexStringToByteArray(IKE_SK_PRF_RESP_HEX_STRING), ikeSaRecord.getSkPr());
ikeSaRecord.close();
verify(mMockFutureRekeyIkeEvent).cancel();
}
// Test generating keying material and building IpSecTransform for making Child SA.
@Test
public void testMakeChildSaRecord() throws Exception {
byte[] sharedKey = new byte[0];
byte[] nonceInit = TestUtils.hexStringToByteArray(IKE_NONCE_INIT_HEX_STRING);
byte[] nonceResp = TestUtils.hexStringToByteArray(IKE_NONCE_RESP_HEX_STRING);
MockIpSecTestUtils mockIpSecTestUtils = MockIpSecTestUtils.setUpMockIpSec();
IpSecManager ipSecManager = mockIpSecTestUtils.getIpSecManager();
IpSecService mockIpSecService = mockIpSecTestUtils.getIpSecService();
Context context = mockIpSecTestUtils.getContext();
when(mockIpSecService.allocateSecurityParameterIndex(
eq(LOCAL_ADDRESS.getHostAddress()), anyInt(), anyObject()))
.thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(FIRST_CHILD_INIT_SPI));
when(mockIpSecService.allocateSecurityParameterIndex(
eq(REMOTE_ADDRESS.getHostAddress()), anyInt(), anyObject()))
.thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(FIRST_CHILD_RESP_SPI));
SecurityParameterIndex childInitSpi =
ipSecManager.allocateSecurityParameterIndex(LOCAL_ADDRESS);
SecurityParameterIndex childRespSpi =
ipSecManager.allocateSecurityParameterIndex(REMOTE_ADDRESS);
byte[] initAuthKey = TestUtils.hexStringToByteArray(FIRST_CHILD_AUTH_INIT_HEX_STRING);
byte[] respAuthKey = TestUtils.hexStringToByteArray(FIRST_CHILD_AUTH_RESP_HEX_STRING);
byte[] initEncryptionKey = TestUtils.hexStringToByteArray(FIRST_CHILD_ENCR_INIT_HEX_STRING);
byte[] respEncryptionKey = TestUtils.hexStringToByteArray(FIRST_CHILD_ENCR_RESP_HEX_STRING);
IIpSecTransformHelper mockIpSecHelper;
mockIpSecHelper = mock(IIpSecTransformHelper.class);
SaRecord.setIpSecTransformHelper(mockIpSecHelper);
IpSecTransform mockInTransform = mock(IpSecTransform.class);
IpSecTransform mockOutTransform = mock(IpSecTransform.class);
UdpEncapsulationSocket mockUdpEncapSocket = mock(UdpEncapsulationSocket.class);
when(mockIpSecHelper.makeIpSecTransform(
eq(context),
eq(LOCAL_ADDRESS),
eq(mockUdpEncapSocket),
eq(childRespSpi),
eq(mHmacSha1IntegrityMac),
eq(mAesCbcCipher),
aryEq(initAuthKey),
aryEq(initEncryptionKey),
eq(false)))
.thenReturn(mockOutTransform);
when(mockIpSecHelper.makeIpSecTransform(
eq(context),
eq(REMOTE_ADDRESS),
eq(mockUdpEncapSocket),
eq(childInitSpi),
eq(mHmacSha1IntegrityMac),
eq(mAesCbcCipher),
aryEq(respAuthKey),
aryEq(respEncryptionKey),
eq(false)))
.thenReturn(mockInTransform);
ChildSaRecordConfig childSaRecordConfig =
new ChildSaRecordConfig(
mockIpSecTestUtils.getContext(),
childInitSpi,
childRespSpi,
LOCAL_ADDRESS,
REMOTE_ADDRESS,
mockUdpEncapSocket,
mIkeHmacSha1Prf,
mHmacSha1IntegrityMac,
mAesCbcCipher,
TestUtils.hexStringToByteArray(IKE_SK_D_HEX_STRING),
false /*isTransport*/,
true /*isLocalInit*/,
mMockFutureRekeyChildEvent);
ChildSaRecord childSaRecord =
mSaRecordHelper.makeChildSaRecord(
sharedKey, nonceInit, nonceResp, childSaRecordConfig);
assertTrue(childSaRecord.isLocalInit);
assertEquals(FIRST_CHILD_INIT_SPI, childSaRecord.getLocalSpi());
assertEquals(FIRST_CHILD_RESP_SPI, childSaRecord.getRemoteSpi());
assertEquals(mockInTransform, childSaRecord.getInboundIpSecTransform());
assertEquals(mockOutTransform, childSaRecord.getOutboundIpSecTransform());
assertArrayEquals(
TestUtils.hexStringToByteArray(FIRST_CHILD_AUTH_INIT_HEX_STRING),
childSaRecord.getOutboundIntegrityKey());
assertArrayEquals(
TestUtils.hexStringToByteArray(FIRST_CHILD_AUTH_RESP_HEX_STRING),
childSaRecord.getInboundIntegrityKey());
assertArrayEquals(
TestUtils.hexStringToByteArray(FIRST_CHILD_ENCR_INIT_HEX_STRING),
childSaRecord.getOutboundEncryptionKey());
assertArrayEquals(
TestUtils.hexStringToByteArray(FIRST_CHILD_ENCR_RESP_HEX_STRING),
childSaRecord.getInboundDecryptionKey());
childSaRecord.close();
verify(mMockFutureRekeyChildEvent).cancel();
SaRecord.setIpSecTransformHelper(new IpSecTransformHelper());
}
}