aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDheeraj Shetty <shettydheeraj@google.com>2020-05-01 15:44:33 -0700
committerDheeraj Shetty <shettydheeraj@google.com>2020-05-04 04:36:59 +0000
commita630efd48373a956972433d0c857aa008d12a76d (patch)
tree1b24bb30c068e99568fa33d1b124b42c2f17c48e
parent5c216abbb4945a9c591e95b86dea2b9dbe4503e0 (diff)
downloadike-a630efd48373a956972433d0c857aa008d12a76d.tar.gz
Use dh group from KE payload for remote rekey
Test: atest FrameworksIkeTest Bug: 138965374 Change-Id: I7765379fd58ab3640db47f7fa6fd7e2149dc0f85 Merged-In: I7765379fd58ab3640db47f7fa6fd7e2149dc0f85
-rw-r--r--src/java/android/net/ipsec/ike/ChildSaProposal.java9
-rw-r--r--src/java/android/net/ipsec/ike/ChildSessionParams.java16
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java35
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineTest.java59
4 files changed, 109 insertions, 10 deletions
diff --git a/src/java/android/net/ipsec/ike/ChildSaProposal.java b/src/java/android/net/ipsec/ike/ChildSaProposal.java
index bf55e8fa..7318659a 100644
--- a/src/java/android/net/ipsec/ike/ChildSaProposal.java
+++ b/src/java/android/net/ipsec/ike/ChildSaProposal.java
@@ -117,6 +117,15 @@ public final class ChildSaProposal extends SaProposal {
&& isTransformSelectedFrom(mEsns, ((ChildSaProposal) saProposal).mEsns);
}
+ /** @hide */
+ public ChildSaProposal getCopyWithAdditionalDhTransform(int dhGroup) {
+ return new ChildSaProposal(
+ getEncryptionTransforms(),
+ getIntegrityTransforms(),
+ new DhGroupTransform[] {new DhGroupTransform(dhGroup)},
+ getEsnTransforms());
+ }
+
/**
* This class is used to incrementally construct a ChildSaProposal. ChildSaProposal instances
* are immutable once built.
diff --git a/src/java/android/net/ipsec/ike/ChildSessionParams.java b/src/java/android/net/ipsec/ike/ChildSessionParams.java
index e34d1d6d..0221491c 100644
--- a/src/java/android/net/ipsec/ike/ChildSessionParams.java
+++ b/src/java/android/net/ipsec/ike/ChildSessionParams.java
@@ -35,6 +35,17 @@ import java.util.concurrent.TimeUnit;
* <p>Note that references to negotiated configurations will be held, and the same parameters will
* be reused during rekey. This includes SA Proposals, lifetimes and traffic selectors.
*
+ * <p>IKE library will send out KE payload only if user has configured one or more DH groups. The KE
+ * payload in a request will use the first DH group from the first user provided SA proposal (or the
+ * peer selected SA proposal if it's a rekey request). The KE payload in a response will depend on
+ * the SA proposal negotiation result.
+ *
+ * <p>When requesting the first Child Session in IKE AUTH, IKE library will not propose any DH group
+ * even if user has configured it, as per RFC 7296. When rekeying this child session, IKE library
+ * will accept DH groups that are configured in its ChildSessionParams. If after rekeying user needs
+ * to have the same DH group as that of the IKE Session, then they need to explicitly set the same
+ * DH Group in ChildSessionParams.
+ *
* @see {@link TunnelModeChildSessionParams} and {@link TransportModeChildSessionParams}
* @hide
*/
@@ -238,8 +249,9 @@ public abstract class ChildSessionParams {
break;
case IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
startAddress = InetAddresses.parseNumericAddress("::");
- endAddress = InetAddresses.parseNumericAddress(
- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+ endAddress =
+ InetAddresses.parseNumericAddress(
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
break;
default:
throw new IllegalArgumentException("Invalid Traffic Selector type: " + tsType);
diff --git a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java b/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java
index 72663a85..8e244946 100644
--- a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java
+++ b/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java
@@ -1482,9 +1482,20 @@ public class ChildSessionStateMachine extends AbstractSessionStateMachine {
IkePayload.getPayloadForTypeInProvidedList(
PAYLOAD_TYPE_SA, IkeSaPayload.class, reqPayloads);
- // TODO: Handle first child remote rekey request with KE payload.
+ IkeKePayload reqKePayload =
+ IkePayload.getPayloadForTypeInProvidedList(
+ PAYLOAD_TYPE_KE, IkeKePayload.class, reqPayloads);
+
+ ChildSaProposal saProposal = mSaProposal;
- byte respProposalNumber = reqSaPayload.getNegotiatedProposalNumber(mSaProposal);
+ // Try accepting a DH group requested during remote rekey for both first and
+ // additional Child Sessions even if it is different from the previously negotiated
+ // proposal.
+ if (reqKePayload != null && isKePayloadAcceptable(reqKePayload)) {
+ saProposal = mSaProposal.getCopyWithAdditionalDhTransform(reqKePayload.dhGroup);
+ }
+
+ byte respProposalNumber = reqSaPayload.getNegotiatedProposalNumber(saProposal);
respPayloads =
CreateChildSaHelper.getRekeyChildCreateRespPayloads(
@@ -1492,7 +1503,7 @@ public class ChildSessionStateMachine extends AbstractSessionStateMachine {
mIpSecSpiGenerator,
mLocalAddress,
respProposalNumber,
- mSaProposal,
+ saProposal,
mLocalTs,
mRemoteTs,
mCurrentChildSaRecord.getLocalSpi(),
@@ -1519,8 +1530,8 @@ public class ChildSessionStateMachine extends AbstractSessionStateMachine {
switch (createChildResult.status) {
case CREATE_STATUS_OK:
try {
- // Do not need to update the negotiated proposal and TS
- // because they are not changed.
+ // Do not need to update TS because they are not changed.
+ mSaProposal = createChildResult.negotiatedProposal;
ChildLocalRequest rekeyLocalRequest = makeRekeyLocalRequest();
@@ -1604,6 +1615,20 @@ public class ChildSessionStateMachine extends AbstractSessionStateMachine {
}
}
+ private boolean isKePayloadAcceptable(IkeKePayload reqKePayload) {
+ ChildSaProposal proposal =
+ mSaProposal.getCopyWithAdditionalDhTransform(reqKePayload.dhGroup);
+
+ // Verify if this proposal is accepted by user
+ for (SaProposal saProposal : mChildSessionParams.getSaProposals()) {
+ if (proposal.isNegotiatedFrom(saProposal)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private void handleCreationFailureAndBackToIdle(IkeProtocolException e) {
loge("Received invalid Rekey Child request. Reject with error notification", e);
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineTest.java
index eab7f4a6..99f6d2e7 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineTest.java
@@ -77,6 +77,7 @@ import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.ChildSessionParams;
import android.net.ipsec.ike.IkeManager;
+import android.net.ipsec.ike.IkeSaProposal;
import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.SaProposal;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
@@ -1675,7 +1676,7 @@ public final class ChildSessionStateMachineTest {
@Test
public void testFirstChildLocalRekey() throws Exception {
- ChildSaProposal saProposal = buildSaProposalWithDhGroup();
+ ChildSaProposal saProposal = buildSaProposalWithDhGroup(SaProposal.DH_GROUP_2048_BIT_MODP);
ChildSessionParams childSessionParams =
new TunnelModeChildSessionParams.Builder()
.addSaProposal(saProposal)
@@ -1694,9 +1695,11 @@ public final class ChildSessionStateMachineTest {
// Send Rekey-Create request
mChildSessionStateMachine.rekeyChildSession();
mLooper.dispatchAll();
+
assertTrue(
mChildSessionStateMachine.getCurrentState()
instanceof ChildSessionStateMachine.RekeyChildLocalCreate);
+
verifyOutboundRekeyKePayload(false /*isResp*/);
}
@@ -1731,12 +1734,62 @@ public final class ChildSessionStateMachineTest {
mMockChildSessionSmCallback);
}
- private ChildSaProposal buildSaProposalWithDhGroup() {
+ private ChildSaProposal buildSaProposalWithDhGroup(int dhGroup) {
return new ChildSaProposal.Builder()
.addEncryptionAlgorithm(
SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
- .addDhGroup(SaProposal.DH_GROUP_2048_BIT_MODP)
+ .addDhGroup(dhGroup)
.build();
}
+
+ @Test
+ public void testRemoteRekeyWithKePayload() throws Exception {
+ // Use child session params with dh group to initiate the state machine
+ ChildSaProposal saProposal = buildSaProposalWithDhGroup(SaProposal.DH_GROUP_2048_BIT_MODP);
+ ChildSessionParams childSessionParams =
+ new TunnelModeChildSessionParams.Builder()
+ .addSaProposal(saProposal)
+ .addInternalAddressRequest(AF_INET)
+ .addInternalAddressRequest(INTERNAL_ADDRESS)
+ .build();
+ mChildSessionStateMachine = buildChildSession(childSessionParams);
+ mChildSessionStateMachine.setDbg(true);
+ mChildSessionStateMachine.start();
+
+ setupIdleStateMachine();
+
+ // Setup for new Child SA negotiation.
+ setUpSpiResource(LOCAL_ADDRESS, REMOTE_INIT_NEW_CHILD_SA_SPI_IN);
+ setUpSpiResource(REMOTE_ADDRESS, REMOTE_INIT_NEW_CHILD_SA_SPI_OUT);
+
+ IkeSaPayload saPayload =
+ IkeSaPayload.createChildSaRequestPayload(
+ new ChildSaProposal[] {saProposal}, mIpSecSpiGenerator, LOCAL_ADDRESS);
+ List<IkePayload> rekeyReqPayloads =
+ makeInboundRekeyChildPayloads(
+ REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, saPayload, false /*isLocalInitRekey*/);
+
+ rekeyReqPayloads.add(
+ new IkeKePayload(IkeSaProposal.DH_GROUP_2048_BIT_MODP, createMockRandomFactory()));
+
+ when(mMockSaRecordHelper.makeChildSaRecord(
+ eq(rekeyReqPayloads), any(List.class), any(ChildSaRecordConfig.class)))
+ .thenReturn(mSpyRemoteInitNewChildSaRecord);
+
+ assertEquals(0, mChildSessionStateMachine.mSaProposal.getDhGroups().size());
+
+ // Receive rekey Child request
+ mChildSessionStateMachine.receiveRequest(
+ IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads);
+ mLooper.dispatchAll();
+
+ assertTrue(
+ mChildSessionStateMachine.getCurrentState()
+ instanceof ChildSessionStateMachine.RekeyChildRemoteDelete);
+
+ verifyOutboundRekeyKePayload(true /*isResp*/);
+
+ assertEquals(1, mChildSessionStateMachine.mSaProposal.getDhGroups().size());
+ }
}