Inject SecureRandom in SPI generation
Create SPI generator for IKE and IPsec SPI that can take a
RandomnessFactory and use return value of #getRandom to allocate
SPI. When the RandomnessFactory returns a DeterministicRandom,
the generator can generate deterministic SPI to support test mode.
Bug: 148689509
Test: atest FrameworksIkeTests
Change-Id: I477a02bc9924dd8c35dda19c53598167f9960075
Merged-In: I477a02bc9924dd8c35dda19c53598167f9960075
(cherry picked from commit 33b694e5f8c53e3f0e561db7793769eb9a7c769f)
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 2dfdb8f..6cdcd26 100644
--- a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java
+++ b/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java
@@ -93,6 +93,7 @@
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.ChildProposal;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
import com.android.internal.net.ipsec.ike.message.IkeTsPayload;
+import com.android.internal.net.ipsec.ike.utils.IpSecSpiGenerator;
import com.android.internal.util.State;
import java.io.IOException;
@@ -154,6 +155,12 @@
private final AlarmManager mAlarmManager;
private final IpSecManager mIpSecManager;
+ /**
+ * mIpSecSpiGenerator will be used by all Child SA creations in this Child Session to avoid SPI
+ * collision in test mode.
+ */
+ private final IpSecSpiGenerator mIpSecSpiGenerator;
+
/** User provided configurations. */
@VisibleForTesting final ChildSessionParams mChildSessionParams;
@@ -231,6 +238,7 @@
int ikeSessionUniqueId,
AlarmManager alarmManager,
IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
ChildSessionParams sessionParams,
Executor userCbExecutor,
ChildSessionCallback userCallback,
@@ -241,6 +249,7 @@
mIkeSessionId = ikeSessionUniqueId;
mAlarmManager = alarmManager;
mIpSecManager = ipSecManager;
+ mIpSecSpiGenerator = ipSecSpiGenerator;
mChildSessionParams = sessionParams;
mUserCallback = userCallback;
@@ -706,7 +715,7 @@
exchangeType,
expectedExchangeType,
mChildSessionParams.isTransportMode(),
- mIpSecManager,
+ mIpSecSpiGenerator,
mRemoteAddress);
switch (createChildResult.status) {
case CREATE_STATUS_OK:
@@ -919,7 +928,7 @@
try {
mRequestPayloads =
CreateChildSaHelper.getInitChildCreateReqPayloads(
- mIpSecManager,
+ mIpSecSpiGenerator,
mLocalAddress,
mChildSessionParams,
false /*isFirstChildSa*/);
@@ -937,7 +946,7 @@
false /*isResp*/,
mRequestPayloads,
ChildSessionStateMachine.this);
- } catch (ResourceUnavailableException e) {
+ } catch (SpiUnavailableException | ResourceUnavailableException e) {
// Fail to assign SPI
handleChildFatalError(e);
}
@@ -1253,7 +1262,7 @@
// Build request with negotiated proposal and TS.
mRequestPayloads =
CreateChildSaHelper.getRekeyChildCreateReqPayloads(
- mIpSecManager,
+ mIpSecSpiGenerator,
mLocalAddress,
mSaProposal,
mLocalTs,
@@ -1265,7 +1274,7 @@
false /*isResp*/,
mRequestPayloads,
ChildSessionStateMachine.this);
- } catch (ResourceUnavailableException e) {
+ } catch (SpiUnavailableException | ResourceUnavailableException e) {
loge("Fail to assign Child SPI. Schedule a retry for rekey Child");
mChildSmCallback.scheduleRetryLocalRequest(
(ChildLocalRequest) mCurrentChildSaRecord.getFutureRekeyEvent());
@@ -1286,7 +1295,7 @@
EXCHANGE_TYPE_CREATE_CHILD_SA,
mChildSessionParams.isTransportMode(),
mCurrentChildSaRecord,
- mIpSecManager,
+ mIpSecSpiGenerator,
mRemoteAddress);
switch (createChildResult.status) {
@@ -1437,7 +1446,7 @@
respPayloads =
CreateChildSaHelper.getRekeyChildCreateRespPayloads(
- mIpSecManager,
+ mIpSecSpiGenerator,
mLocalAddress,
respProposalNumber,
mSaProposal,
@@ -1448,7 +1457,7 @@
} catch (NoValidProposalChosenException e) {
handleCreationFailureAndBackToIdle(e);
return;
- } catch (ResourceUnavailableException e) {
+ } catch (SpiUnavailableException | ResourceUnavailableException e) {
handleCreationFailureAndBackToIdle(
new NoValidProposalChosenException("Fail to assign inbound SPI", e));
return;
@@ -1461,7 +1470,7 @@
req.exchangeType /*exchangeType*/,
EXCHANGE_TYPE_CREATE_CHILD_SA /*expectedExchangeType*/,
mChildSessionParams.isTransportMode(),
- mIpSecManager,
+ mIpSecSpiGenerator,
mRemoteAddress);
switch (createChildResult.status) {
@@ -1759,11 +1768,11 @@
static class CreateChildSaHelper {
/** Create payload list for creating the initial Child SA for this Child Session. */
public static List<IkePayload> getInitChildCreateReqPayloads(
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress localAddress,
ChildSessionParams childSessionParams,
boolean isFirstChildSa)
- throws ResourceUnavailableException {
+ throws SpiUnavailableException, ResourceUnavailableException {
ChildSaProposal[] saProposals = childSessionParams.getSaProposalsInternal();
@@ -1778,7 +1787,7 @@
List<IkePayload> payloadList =
getChildCreatePayloads(
IkeSaPayload.createChildSaRequestPayload(
- saProposals, ipSecManager, localAddress),
+ saProposals, ipSecSpiGenerator, localAddress),
childSessionParams.getInboundTrafficSelectorsInternal(),
childSessionParams.getOutboundTrafficSelectorsInternal(),
childSessionParams.isTransportMode(),
@@ -1796,19 +1805,19 @@
/** Create payload list as a rekey Child Session request. */
public static List<IkePayload> getRekeyChildCreateReqPayloads(
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress localAddress,
ChildSaProposal currentProposal,
IkeTrafficSelector[] currentLocalTs,
IkeTrafficSelector[] currentRemoteTs,
int localSpi,
boolean isTransport)
- throws ResourceUnavailableException {
+ throws SpiUnavailableException, ResourceUnavailableException {
List<IkePayload> payloads =
getChildCreatePayloads(
IkeSaPayload.createChildSaRequestPayload(
new ChildSaProposal[] {currentProposal},
- ipSecManager,
+ ipSecSpiGenerator,
localAddress),
currentLocalTs,
currentRemoteTs,
@@ -1823,7 +1832,7 @@
/** Create payload list as a rekey Child Session response. */
public static List<IkePayload> getRekeyChildCreateRespPayloads(
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress localAddress,
byte proposalNumber,
ChildSaProposal currentProposal,
@@ -1831,11 +1840,14 @@
IkeTrafficSelector[] currentRemoteTs,
int localSpi,
boolean isTransport)
- throws ResourceUnavailableException {
+ throws SpiUnavailableException, ResourceUnavailableException {
List<IkePayload> payloads =
getChildCreatePayloads(
IkeSaPayload.createChildSaResponsePayload(
- proposalNumber, currentProposal, ipSecManager, localAddress),
+ proposalNumber,
+ currentProposal,
+ ipSecSpiGenerator,
+ localAddress),
currentRemoteTs /*initTs*/,
currentLocalTs /*respTs*/,
isTransport,
@@ -1887,7 +1899,7 @@
@ExchangeType int exchangeType,
@ExchangeType int expectedExchangeType,
boolean expectTransport,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress remoteAddress) {
return validateAndNegotiateChild(
@@ -1897,7 +1909,7 @@
expectedExchangeType,
true /*isLocalInit*/,
expectTransport,
- ipSecManager,
+ ipSecSpiGenerator,
remoteAddress);
}
@@ -1911,7 +1923,7 @@
@ExchangeType int exchangeType,
@ExchangeType int expectedExchangeType,
boolean expectTransport,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress remoteAddress) {
// It is guaranteed that a Rekey-Notify Payload with remote SPI of current Child SA is
@@ -1923,7 +1935,7 @@
expectedExchangeType,
false /*isLocalInit*/,
expectTransport,
- ipSecManager,
+ ipSecSpiGenerator,
remoteAddress);
}
@@ -1938,7 +1950,7 @@
@ExchangeType int expectedExchangeType,
boolean expectTransport,
ChildSaRecord expectedChildRecord,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress remoteAddress) {
// Validate rest of payloads and negotiate Child SA.
CreateChildResult childResult =
@@ -1949,7 +1961,7 @@
expectedExchangeType,
true /*isLocalInit*/,
expectTransport,
- ipSecManager,
+ ipSecSpiGenerator,
remoteAddress);
// TODO: Validate new Child SA does not have different Traffic Selectors
@@ -1987,7 +1999,7 @@
@ExchangeType int expectedExchangeType,
boolean isLocalInit,
boolean expectTransport,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress remoteAddress) {
List<IkePayload> inboundPayloads = isLocalInit ? respPayloads : reqPayloads;
@@ -2060,7 +2072,7 @@
// inside.
childProposalPair =
IkeSaPayload.getVerifiedNegotiatedChildProposalPair(
- reqSaPayload, respSaPayload, ipSecManager, remoteAddress);
+ reqSaPayload, respSaPayload, ipSecSpiGenerator, remoteAddress);
ChildSaProposal saProposal = childProposalPair.second.saProposal;
validateKePayloads(inboundPayloads, isLocalInit /*isResp*/, saProposal);
diff --git a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineFactory.java b/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineFactory.java
index f8059bd..32a481c 100644
--- a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineFactory.java
+++ b/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineFactory.java
@@ -25,6 +25,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.ipsec.ike.ChildSessionStateMachine.IChildSessionSmCallback;
+import com.android.internal.net.ipsec.ike.utils.IpSecSpiGenerator;
import java.util.concurrent.Executor;
@@ -40,6 +41,7 @@
Context context,
int ikeSessionUniqueId,
AlarmManager alarmManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
ChildSessionParams sessionParams,
Executor userCbExecutor,
ChildSessionCallback userCallbacks,
@@ -49,6 +51,7 @@
context,
ikeSessionUniqueId,
alarmManager,
+ ipSecSpiGenerator,
sessionParams,
userCbExecutor,
userCallbacks,
@@ -72,6 +75,7 @@
Context context,
int ikeSessionUniqueId,
AlarmManager alarmManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
ChildSessionParams sessionParams,
Executor userCbExecutor,
ChildSessionCallback userCallbacks,
@@ -89,6 +93,7 @@
Context context,
int ikeSessionUniqueId,
AlarmManager alarmManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
ChildSessionParams sessionParams,
Executor userCbExecutor,
ChildSessionCallback userCallbacks,
@@ -100,6 +105,7 @@
ikeSessionUniqueId,
alarmManager,
(IpSecManager) context.getSystemService(Context.IPSEC_SERVICE),
+ ipSecSpiGenerator,
sessionParams,
userCbExecutor,
userCallbacks,
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
index 694a1a4..d4257bc 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
+++ b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
@@ -53,6 +53,7 @@
import android.content.IntentFilter;
import android.net.IpSecManager;
import android.net.IpSecManager.ResourceUnavailableException;
+import android.net.IpSecManager.SpiUnavailableException;
import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.Network;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -128,6 +129,8 @@
import com.android.internal.net.ipsec.ike.message.IkeVendorPayload;
import com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver;
import com.android.internal.net.ipsec.ike.utils.IkeSecurityParameterIndex;
+import com.android.internal.net.ipsec.ike.utils.IkeSpiGenerator;
+import com.android.internal.net.ipsec.ike.utils.IpSecSpiGenerator;
import com.android.internal.net.ipsec.ike.utils.RandomnessFactory;
import com.android.internal.net.ipsec.ike.utils.Retransmitter;
import com.android.internal.util.State;
@@ -354,6 +357,17 @@
/** Package private */
@VisibleForTesting final RandomnessFactory mRandomFactory;
+ /**
+ * mIkeSpiGenerator will be used by all IKE SA creations in this IKE Session to avoid SPI
+ * collision in test mode.
+ */
+ private final IkeSpiGenerator mIkeSpiGenerator;
+ /**
+ * mIpSecSpiGenerator will be shared by all Child Sessions under this IKE Session to avoid SPI
+ * collision in test mode.
+ */
+ private final IpSecSpiGenerator mIpSecSpiGenerator;
+
@VisibleForTesting
@GuardedBy("mChildCbToSessions")
final HashMap<ChildSessionCallback, ChildSessionStateMachine> mChildCbToSessions =
@@ -503,6 +517,8 @@
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mRandomFactory = new RandomnessFactory(mContext, mIkeSessionParams.getNetwork());
+ mIkeSpiGenerator = new IkeSpiGenerator(mRandomFactory);
+ mIpSecSpiGenerator = new IpSecSpiGenerator(mIpSecManager, mRandomFactory);
mIkeSessionCallback = ikeSessionCallback;
@@ -594,6 +610,7 @@
mContext,
mIkeSessionId,
mAlarmManager,
+ mIpSecSpiGenerator,
childParams,
mUserCbExecutor,
callbacks,
@@ -2001,7 +2018,10 @@
List<IkePayload> payloadList =
CreateIkeSaHelper.getRekeyIkeSaResponsePayloads(
- respProposalNumber, mSaProposal, mLocalAddress);
+ respProposalNumber,
+ mSaProposal,
+ mIkeSpiGenerator,
+ mLocalAddress);
// Build IKE header
IkeHeader ikeHeader =
@@ -2725,8 +2745,8 @@
private IkeMessage buildIkeInitReq() throws IOException {
// Generate IKE SPI
- mLocalIkeSpiResource =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(mLocalAddress);
+ mLocalIkeSpiResource = mIkeSpiGenerator.allocateSpi(mLocalAddress);
+
long initSpi = mLocalIkeSpiResource.getSpi();
long respSpi = 0;
@@ -2778,8 +2798,7 @@
throws IkeProtocolException, IOException {
IkeHeader respIkeHeader = respMsg.ikeHeader;
mRemoteIkeSpiResource =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(
- mRemoteAddress, respIkeHeader.ikeResponderSpi);
+ mIkeSpiGenerator.allocateSpi(mRemoteAddress, respIkeHeader.ikeResponderSpi);
int exchangeType = respIkeHeader.exchangeType;
if (exchangeType != IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT) {
@@ -2872,7 +2891,7 @@
reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
mSaProposal =
IkeSaPayload.getVerifiedNegotiatedIkeProposalPair(
- reqSaPayload, respSaPayload, mRemoteAddress)
+ reqSaPayload, respSaPayload, mIkeSpiGenerator, mRemoteAddress)
.second
.saProposal;
@@ -3157,7 +3176,7 @@
mUseEap =
(IkeSessionParams.IKE_AUTH_METHOD_EAP
== mIkeSessionParams.getLocalAuthConfig().mAuthMethod);
- } catch (ResourceUnavailableException e) {
+ } catch (SpiUnavailableException | ResourceUnavailableException e) {
// Handle IPsec SPI assigning failure.
handleIkeFatalError(e);
}
@@ -3217,7 +3236,8 @@
handleIkeFatalError(ikeException);
}
- private IkeMessage buildIkeAuthReq() throws ResourceUnavailableException {
+ private IkeMessage buildIkeAuthReq()
+ throws SpiUnavailableException, ResourceUnavailableException {
List<IkePayload> payloadList = new LinkedList<>();
// Build Identification payloads
@@ -3283,7 +3303,7 @@
payloadList.addAll(
CreateChildSaHelper.getInitChildCreateReqPayloads(
- mIpSecManager,
+ mIpSecSpiGenerator,
mLocalAddress,
mFirstChildSessionParams,
true /*isFirstChildSa*/));
@@ -3486,6 +3506,7 @@
IkeSessionParams.IkeAuthEapConfig ikeAuthEapConfig =
(IkeSessionParams.IkeAuthEapConfig) mIkeSessionParams.getLocalAuthConfig();
+ // TODO(b/148689509): Pass in deterministic random when test mode is enabled
mEapAuthenticator =
mEapAuthenticatorFactory.newEapAuthenticator(
getHandler().getLooper(),
@@ -3881,7 +3902,7 @@
// Throw exception or return valid negotiated proposal with allocated SPIs
negotiatedProposals =
IkeSaPayload.getVerifiedNegotiatedIkeProposalPair(
- reqSaPayload, respSaPayload, mRemoteAddress);
+ reqSaPayload, respSaPayload, mIkeSpiGenerator, mRemoteAddress);
IkeProposal reqProposal = negotiatedProposals.first;
IkeProposal respProposal = negotiatedProposals.second;
@@ -3972,7 +3993,8 @@
// No need to allocate SPIs; they will be allocated as part of the
// getRekeyIkeSaRequestPayloads
List<IkePayload> payloadList =
- CreateIkeSaHelper.getRekeyIkeSaRequestPayloads(saProposals, mLocalAddress);
+ CreateIkeSaHelper.getRekeyIkeSaRequestPayloads(
+ saProposals, mIkeSpiGenerator, mLocalAddress);
// Build IKE header
IkeHeader ikeHeader =
@@ -4655,7 +4677,8 @@
}
public static List<IkePayload> getRekeyIkeSaRequestPayloads(
- IkeSaProposal[] saProposals, InetAddress localAddr) throws IOException {
+ IkeSaProposal[] saProposals, IkeSpiGenerator ikeSpiGenerator, InetAddress localAddr)
+ throws IOException {
if (localAddr == null) {
throw new IllegalArgumentException("Local address was null for rekey");
}
@@ -4666,11 +4689,15 @@
return getCreateIkeSaPayloads(
selectedDhGroup,
- IkeSaPayload.createRekeyIkeSaRequestPayload(saProposals, localAddr));
+ IkeSaPayload.createRekeyIkeSaRequestPayload(
+ saProposals, ikeSpiGenerator, localAddr));
}
public static List<IkePayload> getRekeyIkeSaResponsePayloads(
- byte respProposalNumber, IkeSaProposal saProposal, InetAddress localAddr)
+ byte respProposalNumber,
+ IkeSaProposal saProposal,
+ IkeSpiGenerator ikeSpiGenerator,
+ InetAddress localAddr)
throws IOException {
if (localAddr == null) {
throw new IllegalArgumentException("Local address was null for rekey");
@@ -4681,7 +4708,7 @@
return getCreateIkeSaPayloads(
selectedDhGroup,
IkeSaPayload.createRekeyIkeSaResponsePayload(
- respProposalNumber, saProposal, localAddr));
+ respProposalNumber, saProposal, ikeSpiGenerator, localAddr));
}
/**
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java
index 532ee7f..d2dd394 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java
+++ b/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java
@@ -24,7 +24,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.net.IpSecManager;
import android.net.IpSecManager.ResourceUnavailableException;
import android.net.IpSecManager.SecurityParameterIndex;
import android.net.IpSecManager.SpiUnavailableException;
@@ -39,6 +38,8 @@
import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
import com.android.internal.net.ipsec.ike.exceptions.NoValidProposalChosenException;
import com.android.internal.net.ipsec.ike.utils.IkeSecurityParameterIndex;
+import com.android.internal.net.ipsec.ike.utils.IkeSpiGenerator;
+import com.android.internal.net.ipsec.ike.utils.IpSecSpiGenerator;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -108,7 +109,11 @@
/** Package private constructor for building a request for IKE SA initial creation or rekey */
@VisibleForTesting
IkeSaPayload(
- boolean isResp, byte spiSize, IkeSaProposal[] saProposals, InetAddress localAddress)
+ boolean isResp,
+ byte spiSize,
+ IkeSaProposal[] saProposals,
+ IkeSpiGenerator ikeSpiGenerator,
+ InetAddress localAddress)
throws IOException {
this(isResp, spiSize, localAddress);
@@ -120,7 +125,11 @@
// Proposal number must start from 1.
proposalList.add(
IkeProposal.createIkeProposal(
- (byte) (i + 1) /*number*/, spiSize, saProposals[i], localAddress));
+ (byte) (i + 1) /* number */,
+ spiSize,
+ saProposals[i],
+ ikeSpiGenerator,
+ localAddress));
}
getIkeLog().d(TAG, "Generate " + toString());
@@ -133,13 +142,18 @@
byte spiSize,
byte proposalNumber,
IkeSaProposal saProposal,
+ IkeSpiGenerator ikeSpiGenerator,
InetAddress localAddress)
throws IOException {
this(isResp, spiSize, localAddress);
proposalList.add(
IkeProposal.createIkeProposal(
- proposalNumber /*number*/, spiSize, saProposal, localAddress));
+ proposalNumber /* number */,
+ spiSize,
+ saProposal,
+ ikeSpiGenerator,
+ localAddress));
getIkeLog().d(TAG, "Generate " + toString());
}
@@ -162,9 +176,12 @@
* negotiation.
*/
@VisibleForTesting
- IkeSaPayload(ChildSaProposal[] saProposals, IpSecManager ipSecManager, InetAddress localAddress)
- throws ResourceUnavailableException {
- this(false /*isResp*/, ipSecManager, localAddress);
+ IkeSaPayload(
+ ChildSaProposal[] saProposals,
+ IpSecSpiGenerator ipSecSpiGenerator,
+ InetAddress localAddress)
+ throws SpiUnavailableException, ResourceUnavailableException {
+ this(false /* isResp */, ipSecSpiGenerator, localAddress);
if (saProposals.length < 1) {
throw new IllegalArgumentException("Invalid SA payload.");
@@ -176,7 +193,10 @@
// Proposal number must start from 1.
proposalList.add(
ChildProposal.createChildProposal(
- (byte) (i + 1) /*number*/, saProposals[i], ipSecManager, localAddress));
+ (byte) (i + 1) /* number */,
+ saProposals[i],
+ ipSecSpiGenerator,
+ localAddress));
}
getIkeLog().d(TAG, "Generate " + toString());
@@ -190,20 +210,21 @@
IkeSaPayload(
byte proposalNumber,
ChildSaProposal saProposal,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress localAddress)
- throws ResourceUnavailableException {
- this(true /*isResp*/, ipSecManager, localAddress);
+ throws SpiUnavailableException, ResourceUnavailableException {
+ this(true /* isResp */, ipSecSpiGenerator, localAddress);
proposalList.add(
ChildProposal.createChildProposal(
- proposalNumber /*number*/, saProposal, ipSecManager, localAddress));
+ proposalNumber /* number */, saProposal, ipSecSpiGenerator, localAddress));
getIkeLog().d(TAG, "Generate " + toString());
}
/** Constructor for building an outbound SA Payload for Child SA negotiation. */
- private IkeSaPayload(boolean isResp, IpSecManager ipSecManager, InetAddress localAddress) {
+ private IkeSaPayload(
+ boolean isResp, IpSecSpiGenerator ipSecSpiGenerator, InetAddress localAddress) {
super(IkePayload.PAYLOAD_TYPE_SA, false);
isSaResponse = isResp;
@@ -224,18 +245,26 @@
*/
public static IkeSaPayload createInitialIkeSaPayload(IkeSaProposal[] saProposals)
throws IOException {
- return new IkeSaPayload(false /*isResp*/, SPI_LEN_NOT_INCLUDED, saProposals, null);
+ return new IkeSaPayload(
+ false /* isResp */,
+ SPI_LEN_NOT_INCLUDED,
+ saProposals,
+ null /* ikeSpiGenerator unused */,
+ null /* localAddress unused */);
}
/**
* Construct an instance of IkeSaPayload for building an outbound request for Rekey IKE.
*
* @param saProposals the array of all IKE SA Proposals.
+ * @param ikeSpiGenerator the IKE SPI generator.
* @param localAddress the local address assigned on-device.
*/
public static IkeSaPayload createRekeyIkeSaRequestPayload(
- IkeSaProposal[] saProposals, InetAddress localAddress) throws IOException {
- return new IkeSaPayload(false /*isResp*/, SPI_LEN_IKE, saProposals, localAddress);
+ IkeSaProposal[] saProposals, IkeSpiGenerator ikeSpiGenerator, InetAddress localAddress)
+ throws IOException {
+ return new IkeSaPayload(
+ false /* isResp */, SPI_LEN_IKE, saProposals, ikeSpiGenerator, localAddress);
}
/**
@@ -243,13 +272,22 @@
*
* @param respProposalNumber the selected proposal's number.
* @param saProposal the expected selected IKE SA Proposal.
+ * @param ikeSpiGenerator the IKE SPI generator.
* @param localAddress the local address assigned on-device.
*/
public static IkeSaPayload createRekeyIkeSaResponsePayload(
- byte respProposalNumber, IkeSaProposal saProposal, InetAddress localAddress)
+ byte respProposalNumber,
+ IkeSaProposal saProposal,
+ IkeSpiGenerator ikeSpiGenerator,
+ InetAddress localAddress)
throws IOException {
return new IkeSaPayload(
- true /*isResp*/, SPI_LEN_IKE, respProposalNumber, saProposal, localAddress);
+ true /* isResp */,
+ SPI_LEN_IKE,
+ respProposalNumber,
+ saProposal,
+ ikeSpiGenerator,
+ localAddress);
}
/**
@@ -257,15 +295,17 @@
* negotiation.
*
* @param saProposals the array of all Child SA Proposals.
- * @param ipSecManager the IpSecManager for generating IPsec SPIs.
+ * @param ipSecSpiGenerator the IPsec SPI generator.
* @param localAddress the local address assigned on-device.
* @throws ResourceUnavailableException if too many SPIs are currently allocated for this user.
*/
public static IkeSaPayload createChildSaRequestPayload(
- ChildSaProposal[] saProposals, IpSecManager ipSecManager, InetAddress localAddress)
- throws ResourceUnavailableException {
+ ChildSaProposal[] saProposals,
+ IpSecSpiGenerator ipSecSpiGenerator,
+ InetAddress localAddress)
+ throws SpiUnavailableException, ResourceUnavailableException {
- return new IkeSaPayload(saProposals, ipSecManager, localAddress);
+ return new IkeSaPayload(saProposals, ipSecSpiGenerator, localAddress);
}
/**
@@ -274,16 +314,16 @@
*
* @param respProposalNumber the selected proposal's number.
* @param saProposal the expected selected Child SA Proposal.
- * @param ipSecManager the IpSecManager for generating IPsec SPIs.
+ * @param ipSecSpiGenerator the IPsec SPI generator.
* @param localAddress the local address assigned on-device.
*/
public static IkeSaPayload createChildSaResponsePayload(
byte respProposalNumber,
ChildSaProposal saProposal,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress localAddress)
- throws ResourceUnavailableException {
- return new IkeSaPayload(respProposalNumber, saProposal, ipSecManager, localAddress);
+ throws SpiUnavailableException, ResourceUnavailableException {
+ return new IkeSaPayload(respProposalNumber, saProposal, ipSecSpiGenerator, localAddress);
}
/**
@@ -335,7 +375,10 @@
* the request SA Payload.
*/
public static Pair<IkeProposal, IkeProposal> getVerifiedNegotiatedIkeProposalPair(
- IkeSaPayload reqSaPayload, IkeSaPayload respSaPayload, InetAddress remoteAddress)
+ IkeSaPayload reqSaPayload,
+ IkeSaPayload respSaPayload,
+ IkeSpiGenerator ikeSpiGenerator,
+ InetAddress remoteAddress)
throws NoValidProposalChosenException, IOException {
Pair<Proposal, Proposal> proposalPair =
getVerifiedNegotiatedProposalPair(reqSaPayload, respSaPayload);
@@ -346,12 +389,12 @@
// Allocate initiator's inbound SPI as needed for remotely initiated IKE SA creation
if (reqProposal.spiSize != SPI_NOT_INCLUDED
&& reqProposal.getIkeSpiResource() == null) {
- reqProposal.allocateResourceForRemoteIkeSpi(remoteAddress);
+ reqProposal.allocateResourceForRemoteIkeSpi(ikeSpiGenerator, remoteAddress);
}
// Allocate responder's inbound SPI as needed for locally initiated IKE SA creation
if (respProposal.spiSize != SPI_NOT_INCLUDED
&& respProposal.getIkeSpiResource() == null) {
- respProposal.allocateResourceForRemoteIkeSpi(remoteAddress);
+ respProposal.allocateResourceForRemoteIkeSpi(ikeSpiGenerator, remoteAddress);
}
return new Pair(reqProposal, respProposal);
@@ -384,7 +427,7 @@
*
* @param reqSaPayload the request payload.
* @param respSaPayload the response payload.
- * @param ipSecManager the IpSecManager to allocate SPI resource for the Proposal in this
+ * @param ipSecSpiGenerator the SPI generator to allocate SPI resource for the Proposal in this
* inbound SA Payload.
* @param remoteAddress the address of the remote IKE peer.
* @return the Pair of selected ChildProposal in the locally generated request and the
@@ -397,7 +440,7 @@
public static Pair<ChildProposal, ChildProposal> getVerifiedNegotiatedChildProposalPair(
IkeSaPayload reqSaPayload,
IkeSaPayload respSaPayload,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress remoteAddress)
throws NoValidProposalChosenException, ResourceUnavailableException,
SpiUnavailableException {
@@ -409,11 +452,11 @@
try {
// Allocate initiator's inbound SPI as needed for remotely initiated Child SA creation
if (reqProposal.getChildSpiResource() == null) {
- reqProposal.allocateResourceForRemoteChildSpi(ipSecManager, remoteAddress);
+ reqProposal.allocateResourceForRemoteChildSpi(ipSecSpiGenerator, remoteAddress);
}
// Allocate responder's inbound SPI as needed for locally initiated Child SA creation
if (respProposal.getChildSpiResource() == null) {
- respProposal.allocateResourceForRemoteChildSpi(ipSecManager, remoteAddress);
+ respProposal.allocateResourceForRemoteChildSpi(ipSecSpiGenerator, remoteAddress);
}
return new Pair(reqProposal, respProposal);
@@ -719,7 +762,7 @@
PROTOCOL_ID_IKE,
spiSize,
ikeSpiResource == null ? SPI_NOT_INCLUDED : ikeSpiResource.getSpi(),
- false /*hasUnrecognizedTransform*/);
+ false /* hasUnrecognizedTransform */);
mIkeSpiResource = ikeSpiResource;
this.saProposal = saProposal;
}
@@ -731,14 +774,17 @@
*/
@VisibleForTesting
static IkeProposal createIkeProposal(
- byte number, byte spiSize, IkeSaProposal saProposal, InetAddress localAddress)
+ byte number,
+ byte spiSize,
+ IkeSaProposal saProposal,
+ IkeSpiGenerator ikeSpiGenerator,
+ InetAddress localAddress)
throws IOException {
// IKE_INIT uses SPI_LEN_NOT_INCLUDED, while rekeys use SPI_LEN_IKE
IkeSecurityParameterIndex spiResource =
(spiSize == SPI_LEN_NOT_INCLUDED
? null
- : IkeSecurityParameterIndex.allocateSecurityParameterIndex(
- localAddress));
+ : ikeSpiGenerator.allocateSpi(localAddress));
return new IkeProposal(number, spiSize, spiResource, saProposal);
}
@@ -754,9 +800,9 @@
* Package private method for allocating SPI resource for a validated remotely generated IKE
* SA proposal.
*/
- void allocateResourceForRemoteIkeSpi(InetAddress remoteAddress) throws IOException {
- mIkeSpiResource =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(remoteAddress, spi);
+ void allocateResourceForRemoteIkeSpi(
+ IkeSpiGenerator ikeSpiGenerator, InetAddress remoteAddress) throws IOException {
+ mIkeSpiResource = ikeSpiGenerator.allocateSpi(remoteAddress, spi);
}
@Override
@@ -807,7 +853,7 @@
PROTOCOL_ID_ESP,
SPI_LEN_IPSEC,
(long) childSpiResource.getSpi(),
- false /*hasUnrecognizedTransform*/);
+ false /* hasUnrecognizedTransform */);
mChildSpiResource = childSpiResource;
this.saProposal = saProposal;
}
@@ -821,11 +867,11 @@
static ChildProposal createChildProposal(
byte number,
ChildSaProposal saProposal,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress localAddress)
- throws ResourceUnavailableException {
+ throws SpiUnavailableException, ResourceUnavailableException {
return new ChildProposal(
- number, ipSecManager.allocateSecurityParameterIndex(localAddress), saProposal);
+ number, ipSecSpiGenerator.allocateSpi(localAddress), saProposal);
}
/** Package private method for releasing SPI resource in this unselected Proposal. */
@@ -840,10 +886,10 @@
* Package private method for allocating SPI resource for a validated remotely generated
* Child SA proposal.
*/
- void allocateResourceForRemoteChildSpi(IpSecManager ipSecManager, InetAddress remoteAddress)
+ void allocateResourceForRemoteChildSpi(
+ IpSecSpiGenerator ipSecSpiGenerator, InetAddress remoteAddress)
throws ResourceUnavailableException, SpiUnavailableException {
- mChildSpiResource =
- ipSecManager.allocateSecurityParameterIndex(remoteAddress, (int) spi);
+ mChildSpiResource = ipSecSpiGenerator.allocateSpi(remoteAddress, (int) spi);
}
@Override
diff --git a/src/java/com/android/internal/net/ipsec/ike/utils/IkeSecurityParameterIndex.java b/src/java/com/android/internal/net/ipsec/ike/utils/IkeSecurityParameterIndex.java
index 7f72e11..c5863be 100644
--- a/src/java/com/android/internal/net/ipsec/ike/utils/IkeSecurityParameterIndex.java
+++ b/src/java/com/android/internal/net/ipsec/ike/utils/IkeSecurityParameterIndex.java
@@ -13,15 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.internal.net.ipsec.ike.utils;
import android.util.CloseGuard;
import android.util.Pair;
-import java.io.IOException;
import java.net.InetAddress;
-import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Set;
@@ -40,62 +37,22 @@
* <p>This class follows the pattern of {@link IpSecManager.SecurityParameterIndex}.
*/
public final class IkeSecurityParameterIndex implements AutoCloseable {
- // Remember assigned IKE SPIs to avoid SPI collision.
- private static final Set<Pair<InetAddress, Long>> sAssignedIkeSpis = new HashSet<>();
- private static final int MAX_ASSIGN_IKE_SPI_ATTEMPTS = 100;
- private static final SecureRandom IKE_SPI_RANDOM = new SecureRandom();
+ // Package private Set to remember assigned IKE SPIs to avoid SPI collision. MUST be
+ // accessed only by IkeSecurityParameterIndex and IkeSpiGenerator
+ static final Set<Pair<InetAddress, Long>> sAssignedIkeSpis = new HashSet<>();
private final InetAddress mSourceAddress;
private final long mSpi;
private final CloseGuard mCloseGuard = new CloseGuard();
- private IkeSecurityParameterIndex(InetAddress sourceAddress, long spi) {
+ // Package private constructor that MUST only be called from IkeSpiGenerator
+ IkeSecurityParameterIndex(InetAddress sourceAddress, long spi) {
mSourceAddress = sourceAddress;
mSpi = spi;
mCloseGuard.open("close");
}
/**
- * Get a new IKE SPI and maintain the reservation.
- *
- * @return an instance of IkeSecurityParameterIndex.
- */
- public static IkeSecurityParameterIndex allocateSecurityParameterIndex(
- InetAddress sourceAddress) throws IOException {
- // TODO: Create specific Exception for SPI assigning error.
-
- for (int i = 0; i < MAX_ASSIGN_IKE_SPI_ATTEMPTS; i++) {
- long spi = IKE_SPI_RANDOM.nextLong();
- // Zero value can only be used in the IKE responder SPI field of an IKE INIT
- // request.
- if (spi != 0L
- && sAssignedIkeSpis.add(new Pair<InetAddress, Long>(sourceAddress, spi))) {
- return new IkeSecurityParameterIndex(sourceAddress, spi);
- }
- }
-
- throw new IOException("Failed to generate IKE SPI.");
- }
-
- /**
- * Get a new IKE SPI and maintain the reservation.
- *
- * @return an instance of IkeSecurityParameterIndex.
- */
- public static IkeSecurityParameterIndex allocateSecurityParameterIndex(
- InetAddress sourceAddress, long requestedSpi) throws IOException {
- if (sAssignedIkeSpis.add(new Pair<InetAddress, Long>(sourceAddress, requestedSpi))) {
- return new IkeSecurityParameterIndex(sourceAddress, requestedSpi);
- }
-
- throw new IOException(
- "Failed to generate IKE SPI for "
- + requestedSpi
- + " with source address "
- + sourceAddress.getHostAddress());
- }
-
- /**
* Get the underlying SPI held by this object.
*
* @return the underlying IKE SPI.
diff --git a/src/java/com/android/internal/net/ipsec/ike/utils/IkeSpiGenerator.java b/src/java/com/android/internal/net/ipsec/ike/utils/IkeSpiGenerator.java
new file mode 100644
index 0000000..902d304
--- /dev/null
+++ b/src/java/com/android/internal/net/ipsec/ike/utils/IkeSpiGenerator.java
@@ -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 com.android.internal.net.ipsec.ike.utils;
+
+import android.util.Pair;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.security.SecureRandom;
+
+/** This class provides method to allocate IKE SPI */
+public class IkeSpiGenerator {
+ private final SecureRandom mRandom;
+
+ /**
+ * Constructor of IkeSpiGenerator
+ *
+ * @param secureRandom the seed to generate SPI
+ */
+ public IkeSpiGenerator(RandomnessFactory randomnessFactory) {
+ SecureRandom random = randomnessFactory.getRandom();
+ mRandom = random == null ? new SecureRandom() : random;
+ }
+
+ /**
+ * Get a new IKE SPI and maintain the reservation.
+ *
+ * <p>If this instance is constructed by a spiGenerator, this method will try to allocate SPI
+ * once for the return value of spiGenerator#nextLong. Otherwise, this methods will try multiple
+ * times until it finds an avalaible IKE SPI.
+ *
+ * @return an instance of IkeSecurityParameterIndex.
+ */
+ public IkeSecurityParameterIndex allocateSpi(InetAddress sourceAddress) throws IOException {
+ long spi;
+ do {
+ spi = mRandom.nextLong();
+ } while (spi == 0L
+ || !IkeSecurityParameterIndex.sAssignedIkeSpis.add(
+ new Pair<InetAddress, Long>(sourceAddress, spi)));
+ return new IkeSecurityParameterIndex(sourceAddress, spi);
+ }
+
+ /**
+ * Get a new IKE SPI and maintain the reservation.
+ *
+ * @return an instance of IkeSecurityParameterIndex.
+ */
+ public IkeSecurityParameterIndex allocateSpi(InetAddress sourceAddress, long requestedSpi)
+ throws IOException {
+ if (IkeSecurityParameterIndex.sAssignedIkeSpis.add(
+ new Pair<InetAddress, Long>(sourceAddress, requestedSpi))) {
+ return new IkeSecurityParameterIndex(sourceAddress, requestedSpi);
+ }
+
+ throw new IOException(
+ "Failed to generate IKE SPI for "
+ + requestedSpi
+ + " with source address "
+ + sourceAddress.getHostAddress());
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/utils/IpSecSpiGenerator.java b/src/java/com/android/internal/net/ipsec/ike/utils/IpSecSpiGenerator.java
new file mode 100644
index 0000000..8802898
--- /dev/null
+++ b/src/java/com/android/internal/net/ipsec/ike/utils/IpSecSpiGenerator.java
@@ -0,0 +1,72 @@
+/*
+ * 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 com.android.internal.net.ipsec.ike.utils;
+
+import android.annotation.NonNull;
+import android.net.IpSecManager;
+import android.net.IpSecManager.ResourceUnavailableException;
+import android.net.IpSecManager.SecurityParameterIndex;
+import android.net.IpSecManager.SpiUnavailableException;
+
+import java.net.InetAddress;
+import java.security.SecureRandom;
+import java.util.Objects;
+
+/** This class provides method to allocate IPsec SPI */
+public class IpSecSpiGenerator {
+ private final IpSecManager mIpSecManager;
+ private final SecureRandom mRandom;
+
+ /**
+ * Constructor of IpSecSpiGenerator
+ *
+ * @param secureRandom the seed to generate SPI
+ */
+ public IpSecSpiGenerator(
+ @NonNull IpSecManager ipSecManager, RandomnessFactory randomnessFactory) {
+ Objects.requireNonNull(ipSecManager);
+ mIpSecManager = ipSecManager;
+ mRandom = randomnessFactory.getRandom();
+ }
+
+ /**
+ * Get a new IPsec SPI and maintain the reservation.
+ *
+ * <p>If this instance is constructed by a spiGenerator, this method will try to allocate SPI
+ * once for the return value of spiGenerator#nextInt. Otherwise the SPI will be allocated by the
+ * Kernel.
+ *
+ * @return an instance of SecurityParameterIndex.
+ */
+ public SecurityParameterIndex allocateSpi(InetAddress sourceAddress)
+ throws SpiUnavailableException, ResourceUnavailableException {
+ if (mRandom == null) {
+ return mIpSecManager.allocateSecurityParameterIndex(sourceAddress);
+ } else {
+ return mIpSecManager.allocateSecurityParameterIndex(sourceAddress, mRandom.nextInt());
+ }
+ }
+
+ /**
+ * Get a new IPsec SPI and maintain the reservation.
+ *
+ * @return an instance of SecurityParameterIndex.
+ */
+ public SecurityParameterIndex allocateSpi(InetAddress sourceAddress, int requestedSpi)
+ throws SpiUnavailableException, ResourceUnavailableException {
+ return mIpSecManager.allocateSecurityParameterIndex(sourceAddress, requestedSpi);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/internal/net/TestUtils.java b/tests/iketests/src/java/com/android/internal/net/TestUtils.java
index 6dd5ce5..0b344cd 100644
--- a/tests/iketests/src/java/com/android/internal/net/TestUtils.java
+++ b/tests/iketests/src/java/com/android/internal/net/TestUtils.java
@@ -19,13 +19,16 @@
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import com.android.internal.net.ipsec.ike.utils.RandomnessFactory;
import com.android.internal.net.utils.Log;
import java.nio.ByteBuffer;
-/** TestUtils provides utility methods for parsing Hex String and constructing testing Logger. */
+/** TestUtils provides utility methods to facilitate IKE unit tests */
public class TestUtils {
public static byte[] hexStringToByteArray(String hexString) {
int len = hexString.length();
@@ -110,4 +113,10 @@
return spyLog;
}
+
+ public static RandomnessFactory createMockRandomFactory() {
+ RandomnessFactory rFactory = mock(RandomnessFactory.class);
+ doReturn(null).when(rFactory).getRandom();
+ return rFactory;
+ }
}
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 d0fccfd..7ce4c3f 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
@@ -21,6 +21,7 @@
import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
import static android.system.OsConstants.AF_INET;
+import static com.android.internal.net.TestUtils.createMockRandomFactory;
import static com.android.internal.net.ipsec.ike.ChildSessionStateMachine.CMD_FORCE_TRANSITION;
import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_CHILD;
import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IKE_EXCHANGE_SUBTYPE_DELETE_CHILD;
@@ -117,6 +118,7 @@
import com.android.internal.net.ipsec.ike.message.IkeTestUtils;
import com.android.internal.net.ipsec.ike.message.IkeTsPayload;
import com.android.internal.net.ipsec.ike.testutils.MockIpSecTestUtils;
+import com.android.internal.net.ipsec.ike.utils.IpSecSpiGenerator;
import com.android.internal.net.utils.Log;
import com.android.server.IpSecService;
@@ -186,6 +188,7 @@
private UdpEncapsulationSocket mMockUdpEncapSocket;
private TestLooper mLooper;
+ private IpSecSpiGenerator mIpSecSpiGenerator;
private ChildSessionStateMachine mChildSessionStateMachine;
private List<IkePayload> mFirstSaReqPayloads = new LinkedList<>();
@@ -250,6 +253,8 @@
mMockIpSecManager = new IpSecManager(mContext, mMockIpSecService);
mMockUdpEncapSocket = mock(UdpEncapsulationSocket.class);
+ mIpSecSpiGenerator = new IpSecSpiGenerator(mMockIpSecManager, createMockRandomFactory());
+
mMockNegotiatedProposal = mock(ChildSaProposal.class);
mSpyUserCbExecutor =
@@ -270,6 +275,7 @@
IKE_SESSION_UNIQUE_ID,
mMockAlarmManager,
mMockIpSecManager,
+ mIpSecSpiGenerator,
mChildSessionParams,
mSpyUserCbExecutor,
mMockChildSessionCallback,
@@ -329,7 +335,7 @@
IkeSaPayload reqSaPayload =
IkeSaPayload.createChildSaRequestPayload(
mChildSessionParams.getSaProposalsInternal(),
- mMockIpSecManager,
+ mIpSecSpiGenerator,
LOCAL_ADDRESS);
mFirstSaReqPayloads.add(reqSaPayload);
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
index a638d04..48d5f2b 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
@@ -27,6 +27,7 @@
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
+import static com.android.internal.net.TestUtils.createMockRandomFactory;
import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE;
import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET;
import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IKE_EXCHANGE_SUBTYPE_DELETE_CHILD;
@@ -151,6 +152,8 @@
import com.android.internal.net.ipsec.ike.testmode.DeterministicSecureRandom;
import com.android.internal.net.ipsec.ike.testutils.CertUtils;
import com.android.internal.net.ipsec.ike.utils.IkeSecurityParameterIndex;
+import com.android.internal.net.ipsec.ike.utils.IkeSpiGenerator;
+import com.android.internal.net.ipsec.ike.utils.IpSecSpiGenerator;
import com.android.internal.net.ipsec.ike.utils.RandomnessFactory;
import com.android.internal.net.ipsec.ike.utils.State;
import com.android.internal.net.utils.Log;
@@ -280,6 +283,11 @@
private static final int PAYLOAD_TYPE_UNSUPPORTED = 127;
+ private static final long RETRANSMIT_BACKOFF_TIMEOUT_MS = 5000L;
+
+ private static final IkeSpiGenerator IKE_SPI_GENERATOR =
+ new IkeSpiGenerator(createMockRandomFactory());
+
private IkeUdpEncapSocket mSpyIkeUdpEncapSocket;
private IkeUdp4Socket mSpyIkeUdp4Socket;
private IkeUdp6Socket mSpyIkeUdp6Socket;
@@ -619,8 +627,8 @@
Inet4Address respAddress = isLocalInit ? REMOTE_ADDRESS : LOCAL_ADDRESS;
return new IkeSaRecord(
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(initAddress, initSpi),
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(respAddress, respSpi),
+ IKE_SPI_GENERATOR.allocateSpi(initAddress, initSpi),
+ IKE_SPI_GENERATOR.allocateSpi(respAddress, respSpi),
isLocalInit,
TestUtils.hexStringToByteArray(NONCE_INIT_HEX_STRING),
TestUtils.hexStringToByteArray(NONCE_RESP_HEX_STRING),
@@ -1173,10 +1181,8 @@
@Test
public void testAllocateIkeSpi() throws Exception {
// Test randomness.
- IkeSecurityParameterIndex ikeSpiOne =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS);
- IkeSecurityParameterIndex ikeSpiTwo =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS);
+ IkeSecurityParameterIndex ikeSpiOne = IKE_SPI_GENERATOR.allocateSpi(LOCAL_ADDRESS);
+ IkeSecurityParameterIndex ikeSpiTwo = IKE_SPI_GENERATOR.allocateSpi(LOCAL_ADDRESS);
assertNotEquals(ikeSpiOne.getSpi(), ikeSpiTwo.getSpi());
ikeSpiTwo.close();
@@ -1184,7 +1190,7 @@
// Test duplicate SPIs.
long spiValue = ikeSpiOne.getSpi();
try {
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS, spiValue);
+ IKE_SPI_GENERATOR.allocateSpi(LOCAL_ADDRESS, spiValue);
fail("Expected to fail because duplicate SPI was assigned to the same address.");
} catch (IOException expected) {
@@ -1192,7 +1198,7 @@
ikeSpiOne.close();
IkeSecurityParameterIndex ikeSpiThree =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS, spiValue);
+ IKE_SPI_GENERATOR.allocateSpi(LOCAL_ADDRESS, spiValue);
ikeSpiThree.close();
}
@@ -1467,6 +1473,7 @@
eq(mSpyContext),
anyInt(),
any(AlarmManager.class),
+ any(IpSecSpiGenerator.class),
eq(mChildSessionParams),
eq(mSpyUserCbExecutor),
any(ChildSessionCallback.class),
@@ -1524,6 +1531,7 @@
eq(mSpyContext),
anyInt(),
any(AlarmManager.class),
+ any(IpSecSpiGenerator.class),
eq(mChildSessionParams),
eq(mSpyUserCbExecutor),
eq(childCallback),
@@ -2285,6 +2293,7 @@
eq(mSpyContext),
anyInt(),
any(AlarmManager.class),
+ any(IpSecSpiGenerator.class),
eq(mChildSessionParams),
eq(mSpyUserCbExecutor),
eq(mMockChildSessionCallback),
@@ -4187,6 +4196,7 @@
eq(mSpyContext),
anyInt(),
any(AlarmManager.class),
+ any(IpSecSpiGenerator.class),
eq(mChildSessionParams),
eq(mSpyUserCbExecutor),
eq(cb),
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/SaRecordTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/SaRecordTest.java
index 0f6bc42..644ba06 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/SaRecordTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/SaRecordTest.java
@@ -16,6 +16,8 @@
package com.android.internal.net.ipsec.ike;
+import static com.android.internal.net.TestUtils.createMockRandomFactory;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -54,6 +56,7 @@
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
import com.android.internal.net.ipsec.ike.testutils.MockIpSecTestUtils;
import com.android.internal.net.ipsec.ike.utils.IkeSecurityParameterIndex;
+import com.android.internal.net.ipsec.ike.utils.IkeSpiGenerator;
import com.android.server.IpSecService;
import org.junit.Before;
@@ -70,6 +73,9 @@
private static final Inet4Address REMOTE_ADDRESS =
(Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100"));
+ private static final IkeSpiGenerator IKE_SPI_GENERATOR =
+ new IkeSpiGenerator(createMockRandomFactory());
+
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 =
@@ -175,11 +181,9 @@
byte[] nonceResp = TestUtils.hexStringToByteArray(IKE_NONCE_RESP_HEX_STRING);
IkeSecurityParameterIndex ikeInitSpi =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(
- LOCAL_ADDRESS, IKE_INIT_SPI);
+ IKE_SPI_GENERATOR.allocateSpi(LOCAL_ADDRESS, IKE_INIT_SPI);
IkeSecurityParameterIndex ikeRespSpi =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(
- REMOTE_ADDRESS, IKE_RESP_SPI);
+ IKE_SPI_GENERATOR.allocateSpi(REMOTE_ADDRESS, IKE_RESP_SPI);
IkeSaRecordConfig ikeSaRecordConfig =
new IkeSaRecordConfig(
ikeInitSpi,
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayloadTest.java
index bf21ad8..4ec6d3b 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayloadTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayloadTest.java
@@ -16,6 +16,8 @@
package com.android.internal.net.ipsec.ike.message;
+import static com.android.internal.net.TestUtils.createMockRandomFactory;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -60,6 +62,8 @@
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.UnrecognizedAttribute;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.UnrecognizedTransform;
import com.android.internal.net.ipsec.ike.testutils.MockIpSecTestUtils;
+import com.android.internal.net.ipsec.ike.utils.IkeSpiGenerator;
+import com.android.internal.net.ipsec.ike.utils.IpSecSpiGenerator;
import com.android.server.IpSecService;
import org.junit.Before;
@@ -160,6 +164,9 @@
private IpSecService mMockIpSecService;
private IpSecManager mIpSecManager;
+ private IkeSpiGenerator mIkeSpiGenerator;
+ private IpSecSpiGenerator mIpSecSpiGenerator;
+
private IpSecSpiResponse mDummyIpSecSpiResponseLocalOne;
private IpSecSpiResponse mDummyIpSecSpiResponseLocalTwo;
private IpSecSpiResponse mDummyIpSecSpiResponseRemote;
@@ -240,6 +247,9 @@
when(mMockIpSecService.allocateSecurityParameterIndex(
eq(REMOTE_ADDRESS.getHostAddress()), anyInt(), anyObject()))
.thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(CHILD_SPI_REMOTE));
+
+ mIkeSpiGenerator = new IkeSpiGenerator(createMockRandomFactory());
+ mIpSecSpiGenerator = new IpSecSpiGenerator(mIpSecManager, createMockRandomFactory());
}
// TODO: Add tearDown() to reset Proposal.sTransformDecoder and Transform.sAttributeDecoder.
@@ -665,6 +675,7 @@
(byte) PROPOSAL_NUMBER,
IkePayload.SPI_LEN_NOT_INCLUDED,
mIkeSaProposalOne,
+ mIkeSpiGenerator,
LOCAL_ADDRESS);
ByteBuffer byteBuffer = ByteBuffer.allocate(proposal.getProposalLength());
@@ -691,7 +702,7 @@
public void testBuildOutboundIkeRekeySaResponsePayload() throws Exception {
IkeSaPayload saPayload =
IkeSaPayload.createRekeyIkeSaResponsePayload(
- (byte) 1, mIkeSaProposalOne, LOCAL_ADDRESS);
+ (byte) 1, mIkeSaProposalOne, mIkeSpiGenerator, LOCAL_ADDRESS);
assertTrue(saPayload.isSaResponse);
assertEquals(1, saPayload.proposalList.size());
@@ -727,7 +738,7 @@
public void testBuildOutboundChildSaRequest() throws Exception {
IkeSaPayload saPayload =
IkeSaPayload.createChildSaRequestPayload(
- mTwoChildSaProposalsArray, mIpSecManager, LOCAL_ADDRESS);
+ mTwoChildSaProposalsArray, mIpSecSpiGenerator, LOCAL_ADDRESS);
assertFalse(saPayload.isSaResponse);
assertEquals(PROPOSAL_NUMBER_LIST.length, saPayload.proposalList.size());
@@ -769,7 +780,7 @@
Pair<IkeProposal, IkeProposal> negotiatedProposalPair =
IkeSaPayload.getVerifiedNegotiatedIkeProposalPair(
- reqPayload, respPayload, REMOTE_ADDRESS);
+ reqPayload, respPayload, mIkeSpiGenerator, REMOTE_ADDRESS);
IkeProposal reqProposal = negotiatedProposalPair.first;
IkeProposal respProposal = negotiatedProposalPair.second;
@@ -790,14 +801,14 @@
private void verifyChildSaNegotiation(
IkeSaPayload reqPayload,
IkeSaPayload respPayload,
- IpSecManager ipSecManager,
+ IpSecSpiGenerator ipSecSpiGenerator,
InetAddress remoteAddress,
boolean isLocalInit)
throws Exception {
// SA negotiation
Pair<ChildProposal, ChildProposal> negotiatedProposalPair =
IkeSaPayload.getVerifiedNegotiatedChildProposalPair(
- reqPayload, respPayload, ipSecManager, remoteAddress);
+ reqPayload, respPayload, ipSecSpiGenerator, remoteAddress);
ChildProposal reqProposal = negotiatedProposalPair.first;
ChildProposal respProposal = negotiatedProposalPair.second;
@@ -822,7 +833,7 @@
// Build local request
IkeSaPayload reqPayload =
IkeSaPayload.createChildSaRequestPayload(
- mTwoChildSaProposalsArray, mIpSecManager, LOCAL_ADDRESS);
+ mTwoChildSaProposalsArray, mIpSecSpiGenerator, LOCAL_ADDRESS);
// Build remote response
Proposal.sTransformDecoder =
@@ -834,7 +845,7 @@
TestUtils.hexStringToByteArray(INBOUND_CHILD_PROPOSAL_RAW_PACKET));
verifyChildSaNegotiation(
- reqPayload, respPayload, mIpSecManager, REMOTE_ADDRESS, true /*isLocalInit*/);
+ reqPayload, respPayload, mIpSecSpiGenerator, REMOTE_ADDRESS, true /*isLocalInit*/);
}
@Test
@@ -857,10 +868,10 @@
// Build local response
IkeSaPayload respPayload =
IkeSaPayload.createChildSaResponsePayload(
- (byte) 1, mChildSaProposalOne, mIpSecManager, LOCAL_ADDRESS);
+ (byte) 1, mChildSaProposalOne, mIpSecSpiGenerator, LOCAL_ADDRESS);
verifyChildSaNegotiation(
- reqPayload, respPayload, mIpSecManager, REMOTE_ADDRESS, false /*isLocalInit*/);
+ reqPayload, respPayload, mIpSecSpiGenerator, REMOTE_ADDRESS, false /*isLocalInit*/);
}
// Test throwing when negotiated proposal in SA response payload has unrecognized Transform.