Decode and validate IKE fragment in IkeMessage
Bug: 122677075
Test: atest frameworksIkeTests (new tests added)
Change-Id: Ib1a2a624804a67597429fab2fb35fdb50e29bffc
diff --git a/src/java/com/android/ike/ikev2/IkeManager.java b/src/java/com/android/ike/ikev2/IkeManager.java
index ab37429..61a67de 100644
--- a/src/java/com/android/ike/ikev2/IkeManager.java
+++ b/src/java/com/android/ike/ikev2/IkeManager.java
@@ -66,8 +66,8 @@
firstChildSessionCallback);
}
- // Package private
- static Log getIkeLog() {
+ /** Returns IKE logger. */
+ public static Log getIkeLog() {
return sIkeLog;
}
diff --git a/src/java/com/android/ike/ikev2/IkeSessionStateMachine.java b/src/java/com/android/ike/ikev2/IkeSessionStateMachine.java
index a90d4df..0ad180c 100644
--- a/src/java/com/android/ike/ikev2/IkeSessionStateMachine.java
+++ b/src/java/com/android/ike/ikev2/IkeSessionStateMachine.java
@@ -1364,7 +1364,8 @@
mIkeCipher,
ikeSaRecord,
ikeHeader,
- ikePacketBytes);
+ ikePacketBytes,
+ null /*collectedFragments*/);
switch (decodeResult.status) {
case DECODE_STATUS_OK:
ikeSaRecord.incrementLocalRequestMessageId();
@@ -1425,7 +1426,8 @@
mIkeCipher,
ikeSaRecord,
ikeHeader,
- ikePacketBytes);
+ ikePacketBytes,
+ null /*collectedFragments*/);
switch (decodeResult.status) {
case DECODE_STATUS_OK:
ikeSaRecord.incrementRemoteRequestMessageId();
@@ -3636,7 +3638,8 @@
mIkeCipher,
ikeSaRecord,
ikeHeader,
- receivedIkePacket.ikePacketBytes);
+ receivedIkePacket.ikePacketBytes,
+ null /*collectedFragments*/);
isMessageOnNewSa =
(decodeResult.status == DECODE_STATUS_PROTECTED_ERROR)
|| (decodeResult.status == DECODE_STATUS_OK);
diff --git a/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBody.java b/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBody.java
index 6967efd..eec75be 100644
--- a/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBody.java
+++ b/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBody.java
@@ -60,7 +60,7 @@
IkeMacIntegrity integrityMac,
IkeCipher decryptCipher,
byte[] integrityKey,
- byte[] decryptKey)
+ byte[] decryptionKey)
throws IkeProtocolException, GeneralSecurityException {
ByteBuffer inputBuffer = ByteBuffer.wrap(message);
@@ -82,7 +82,7 @@
// Authenticate and decrypt.
byte[] dataToAuthenticate = Arrays.copyOfRange(message, 0, message.length - checksumLen);
validateChecksumOrThrow(dataToAuthenticate, integrityMac, integrityKey, mIntegrityChecksum);
- mUnencryptedData = decrypt(mEncryptedAndPaddedData, decryptCipher, decryptKey, mIv);
+ mUnencryptedData = decrypt(mEncryptedAndPaddedData, decryptCipher, decryptionKey, mIv);
}
/**
@@ -204,9 +204,9 @@
/** Package private for testing */
@VisibleForTesting
static byte[] decrypt(
- byte[] encryptedData, IkeCipher decryptCipher, byte[] decryptKey, byte[] iv)
+ byte[] encryptedData, IkeCipher decryptCipher, byte[] decryptionKey, byte[] iv)
throws IllegalBlockSizeException {
- byte[] decryptedPaddedData = decryptCipher.decrypt(encryptedData, decryptKey, iv);
+ byte[] decryptedPaddedData = decryptCipher.decrypt(encryptedData, decryptionKey, iv);
// Remove padding. Pad length value is the last byte of the padded unencrypted data.
int padLength = Byte.toUnsignedInt(decryptedPaddedData[encryptedData.length - 1]);
diff --git a/src/java/com/android/ike/ikev2/message/IkeHeader.java b/src/java/com/android/ike/ikev2/message/IkeHeader.java
index 188a8b0..bf9dc3e 100644
--- a/src/java/com/android/ike/ikev2/message/IkeHeader.java
+++ b/src/java/com/android/ike/ikev2/message/IkeHeader.java
@@ -155,8 +155,8 @@
return mEncodedMessageLength;
}
- /** Validate syntax and major version of inbound IKE header. */
- public void checkInboundValidOrThrow(int packetLength) throws IkeProtocolException {
+ /** Validate major version of inbound IKE header. */
+ public void validateMajorVersion() throws IkeProtocolException {
if (majorVersion > 2) {
// Receive higher version of protocol. Stop parsing.
throw new InvalidMajorVersionException(majorVersion);
@@ -168,6 +168,15 @@
// error.
throw new InvalidSyntaxException("Major version is smaller than 2.");
}
+ }
+
+ /**
+ * Validate syntax of inbound IKE header.
+ *
+ * <p>It MUST only be used for an inbound IKE header because we don't know the outbound message
+ * length before we encode it.
+ */
+ public void validateInboundHeader(int packetLength) throws IkeProtocolException {
if (exchangeType < EXCHANGE_TYPE_IKE_SA_INIT
|| exchangeType > EXCHANGE_TYPE_INFORMATIONAL) {
throw new InvalidSyntaxException("Invalid IKE Exchange Type.");
diff --git a/src/java/com/android/ike/ikev2/message/IkeMessage.java b/src/java/com/android/ike/ikev2/message/IkeMessage.java
index b8eff9a..c3323c2 100644
--- a/src/java/com/android/ike/ikev2/message/IkeMessage.java
+++ b/src/java/com/android/ike/ikev2/message/IkeMessage.java
@@ -16,6 +16,7 @@
package com.android.ike.ikev2.message;
+import static com.android.ike.ikev2.IkeManager.getIkeLog;
import static com.android.ike.ikev2.message.IkePayload.PayloadType;
import android.annotation.IntDef;
@@ -56,6 +57,8 @@
* Protocol Version 2 (IKEv2)</a>
*/
public final class IkeMessage {
+ private static final String TAG = "IkeMessage";
+
private static IIkeMessageHelper sIkeMessageHelper = new IkeMessageHelper();
// Currently use Bouncy Castle as crypto security provider
static final Provider SECURITY_PROVIDER = new BouncyCastleProvider();
@@ -120,6 +123,7 @@
* @param ikeSaRecord ikeSaRecord where this packet is sent on.
* @param ikeHeader header of IKE packet.
* @param packet IKE packet as a byte array.
+ * @param collectedFragments previously received IKE fragments.
* @return the decoding result.
*/
public static DecodeResult decode(
@@ -128,9 +132,16 @@
IkeCipher decryptCipher,
IkeSaRecord ikeSaRecord,
IkeHeader ikeHeader,
- byte[] packet) {
+ byte[] packet,
+ DecodeResultPartial collectedFragments) {
return sIkeMessageHelper.decode(
- expectedMsgId, integrityMac, decryptCipher, ikeSaRecord, ikeHeader, packet);
+ expectedMsgId,
+ integrityMac,
+ decryptCipher,
+ ikeSaRecord,
+ ikeHeader,
+ packet,
+ collectedFragments);
}
private static List<IkePayload> decodePayloadList(
@@ -359,6 +370,7 @@
* @param ikeSaRecord ikeSaRecord where this packet is sent on.
* @param ikeHeader header of IKE packet.
* @param packet IKE packet as a byte array.
+ * @param collectedFragments previously received IKE fragments.
* @return the decoding result.
*/
DecodeResult decode(
@@ -367,7 +379,8 @@
IkeCipher decryptCipher,
IkeSaRecord ikeSaRecord,
IkeHeader ikeHeader,
- byte[] packet);
+ byte[] packet,
+ DecodeResultPartial collectedFragments);
}
/** IkeMessageHelper provides methods for decoding, encoding and processing IKE packet. */
@@ -429,7 +442,8 @@
throw new InvalidMessageIdException(header.messageId);
}
- header.checkInboundValidOrThrow(inputPacket.length);
+ header.validateMajorVersion();
+ header.validateInboundHeader(inputPacket.length);
byte[] unencryptedPayloads =
Arrays.copyOfRange(
@@ -455,7 +469,8 @@
IkeCipher decryptCipher,
IkeSaRecord ikeSaRecord,
IkeHeader ikeHeader,
- byte[] packet) {
+ byte[] packet,
+ DecodeResultPartial collectedFragments) {
return decode(
expectedMsgId,
ikeHeader,
@@ -463,7 +478,8 @@
integrityMac,
decryptCipher,
ikeSaRecord.getInboundIntegrityKey(),
- ikeSaRecord.getInboundDecryptionKey());
+ ikeSaRecord.getInboundDecryptionKey(),
+ collectedFragments);
}
private DecodeResult decode(
@@ -473,62 +489,195 @@
@Nullable IkeMacIntegrity integrityMac,
IkeCipher decryptCipher,
byte[] integrityKey,
- byte[] decryptKey) {
-
- if (header.nextPayloadType != IkePayload.PAYLOAD_TYPE_SK) {
+ byte[] decryptionKey,
+ DecodeResultPartial collectedFragments) {
+ if (header.nextPayloadType != IkePayload.PAYLOAD_TYPE_SK
+ && header.nextPayloadType != IkePayload.PAYLOAD_TYPE_SKF) {
// TODO: b/123372339 Handle message containing unprotected payloads.
throw new UnsupportedOperationException("Message contains unprotected payloads");
}
- // Validate security parameters.
+ // Decrypt message and do authentication
Pair<IkeSkPayload, Integer> pair;
try {
- if (header.messageId != expectedMsgId) {
- throw new InvalidMessageIdException(header.messageId);
- }
pair =
- IkePayloadFactory.getIkeSkPayload(
- false /*isSkf*/,
+ decryptAndAuthenticate(
+ expectedMsgId,
+ header,
inputPacket,
integrityMac,
decryptCipher,
integrityKey,
- decryptKey);
-
- // TODO: Support decoding IkeSkfPayload
- } catch (NegativeArraySizeException | BufferUnderflowException e) {
- return new DecodeResultError(
- DECODE_STATUS_UNPROTECTED_ERROR,
- new InvalidSyntaxException("Malformed IKE Payload"));
- } catch (GeneralSecurityException e) {
- return new DecodeResultError(
- DECODE_STATUS_UNPROTECTED_ERROR, new IkeInternalException(e));
+ decryptionKey);
} catch (IkeException e) {
- return new DecodeResultError(DECODE_STATUS_UNPROTECTED_ERROR, e);
+ if (collectedFragments == null) {
+ return new DecodeResultError(DECODE_STATUS_UNPROTECTED_ERROR, e);
+ } else {
+ getIkeLog()
+ .i(
+ TAG,
+ "Message authentication or decryption failed on received"
+ + " message. Discard it ",
+ e);
+ return collectedFragments;
+ }
}
- // Check is there is protocol error in this IKE message.
+ // Handle IKE fragment
+ boolean isFragment = (header.nextPayloadType == IkePayload.PAYLOAD_TYPE_SKF);
+ boolean fragReassemblyStarted = (collectedFragments != null);
+
+ if (isFragment) {
+ getIkeLog()
+ .d(
+ TAG,
+ "Received an IKE fragment ("
+ + ((IkeSkfPayload) pair.first).fragmentNum
+ + "/"
+ + ((IkeSkfPayload) pair.first).totalFragments
+ + ")");
+ }
+
+ // IKE fragment reassembly has started but a complete message was received.
+ if (!isFragment && fragReassemblyStarted) {
+ getIkeLog()
+ .w(
+ TAG,
+ "Received a complete IKE message while doing IKE fragment"
+ + " reassembly. Discard the newly received message.");
+ return collectedFragments;
+ }
+
+ byte[] decryptedBytes = pair.first.getUnencryptedData();
+ int firstPayloadType = pair.second;
+
+ // Received an IKE fragment
+ if (isFragment) {
+ validateFragmentHeader(header, inputPacket.length, collectedFragments);
+
+ // Add the recently received fragment to the reassembly queue.
+ DecodeResultPartial DecodeResultPartial =
+ processIkeFragment(
+ header,
+ (IkeSkfPayload) (pair.first),
+ pair.second,
+ collectedFragments);
+
+ if (!DecodeResultPartial.isAllFragmentsReceived()) return DecodeResultPartial;
+
+ firstPayloadType = DecodeResultPartial.firstPayloadType;
+ decryptedBytes = DecodeResultPartial.reassembleAllFrags();
+ }
+
+ // Received or has reassembled a complete IKE message. Check if there is protocol error.
try {
- IkeSkPayload skPayload = pair.first;
- int firstPayloadType = pair.second;
+ // TODO: Log IKE header information and payload types
List<IkePayload> supportedPayloadList =
- decodePayloadList(
- firstPayloadType,
- header.isResponseMsg,
- skPayload.getUnencryptedData());
+ decodePayloadList(firstPayloadType, header.isResponseMsg, decryptedBytes);
- header.checkInboundValidOrThrow(inputPacket.length);
+ header.validateInboundHeader(inputPacket.length);
return new DecodeResultOk(new IkeMessage(header, supportedPayloadList));
} catch (NegativeArraySizeException | BufferUnderflowException e) {
// Invalid length error when parsing payload bodies.
return new DecodeResultError(
DECODE_STATUS_PROTECTED_ERROR,
- new InvalidSyntaxException("Malformed IKE Payload"));
+ new InvalidSyntaxException("Malformed IKE Payload", e));
} catch (IkeProtocolException e) {
return new DecodeResultError(DECODE_STATUS_PROTECTED_ERROR, e);
}
}
+
+ private Pair<IkeSkPayload, Integer> decryptAndAuthenticate(
+ int expectedMsgId,
+ IkeHeader header,
+ byte[] inputPacket,
+ @Nullable IkeMacIntegrity integrityMac,
+ IkeCipher decryptCipher,
+ byte[] integrityKey,
+ byte[] decryptionKey)
+ throws IkeException {
+
+ try {
+ if (header.messageId != expectedMsgId) {
+ throw new InvalidMessageIdException(header.messageId);
+ }
+
+ header.validateMajorVersion();
+
+ boolean isSkf = header.nextPayloadType == IkePayload.PAYLOAD_TYPE_SKF;
+ return IkePayloadFactory.getIkeSkPayload(
+ isSkf,
+ inputPacket,
+ integrityMac,
+ decryptCipher,
+ integrityKey,
+ decryptionKey);
+ } catch (NegativeArraySizeException | BufferUnderflowException e) {
+ throw new InvalidSyntaxException("Malformed IKE Payload", e);
+ } catch (GeneralSecurityException e) {
+ throw new IkeInternalException(e);
+ }
+ }
+
+ private void validateFragmentHeader(
+ IkeHeader fragIkeHeader, int packetLen, DecodeResultPartial collectedFragments) {
+ try {
+ fragIkeHeader.validateInboundHeader(packetLen);
+ } catch (IkeProtocolException e) {
+ getIkeLog()
+ .e(
+ TAG,
+ "Received an IKE fragment with invalid header. Will be handled when"
+ + " reassembly is done.",
+ e);
+ }
+
+ if (collectedFragments == null) return;
+ if (fragIkeHeader.exchangeType != collectedFragments.ikeHeader.exchangeType) {
+ getIkeLog()
+ .e(
+ TAG,
+ "Received an IKE fragment with different exchange type from"
+ + " previously collected fragments. Ignore it.");
+ }
+ }
+
+ private DecodeResultPartial processIkeFragment(
+ IkeHeader header,
+ IkeSkfPayload skf,
+ int nextPayloadType,
+ @Nullable DecodeResultPartial collectedFragments) {
+ if (collectedFragments == null) {
+ return new DecodeResultPartial(header, skf, nextPayloadType, collectedFragments);
+ }
+
+ if (skf.totalFragments > collectedFragments.collectedFragsList.length) {
+ getIkeLog()
+ .i(
+ TAG,
+ "Received IKE fragment has larger total fragments number. Discard"
+ + " all previously collected fragments");
+ return new DecodeResultPartial(
+ header, skf, nextPayloadType, null /*collectedFragments*/);
+ }
+
+ if (skf.totalFragments < collectedFragments.collectedFragsList.length) {
+ getIkeLog()
+ .i(
+ TAG,
+ "Received IKE fragment has smaller total fragments number. Discard"
+ + " it.");
+ return collectedFragments;
+ }
+
+ if (collectedFragments.collectedFragsList[skf.fragmentNum - 1] != null) {
+ getIkeLog().i(TAG, "Received IKE fragment is a replay.");
+ return collectedFragments;
+ }
+
+ return new DecodeResultPartial(header, skf, nextPayloadType, collectedFragments);
+ }
}
/** Status to describe the result of decoding an inbound IKE message. */
diff --git a/src/java/com/android/ike/ikev2/message/IkePayloadFactory.java b/src/java/com/android/ike/ikev2/message/IkePayloadFactory.java
index 74dd4c9..0e4290c 100644
--- a/src/java/com/android/ike/ikev2/message/IkePayloadFactory.java
+++ b/src/java/com/android/ike/ikev2/message/IkePayloadFactory.java
@@ -16,6 +16,7 @@
package com.android.ike.ikev2.message;
+import android.annotation.Nullable;
import android.util.Pair;
import com.android.ike.ikev2.crypto.IkeCipher;
@@ -90,6 +91,35 @@
return new IkeUnsupportedPayload(payloadType, isCritical);
}
}
+
+ @Override
+ public IkeSkPayload decodeIkeSkPayload(
+ boolean isSkf,
+ boolean critical,
+ byte[] message,
+ @Nullable IkeMacIntegrity integrityMac,
+ IkeCipher decryptCipher,
+ byte[] integrityKey,
+ byte[] decryptionKey)
+ throws IkeProtocolException, GeneralSecurityException {
+ if (isSkf) {
+ return new IkeSkfPayload(
+ critical,
+ message,
+ integrityMac,
+ decryptCipher,
+ integrityKey,
+ decryptionKey);
+ } else {
+ return new IkeSkPayload(
+ critical,
+ message,
+ integrityMac,
+ decryptCipher,
+ integrityKey,
+ decryptionKey);
+ }
+ }
}
/**
@@ -134,7 +164,7 @@
* @param integrityMac the negotiated integrity algorithm.
* @param decryptCipher the negotiated encryption algorithm.
* @param integrityKey the negotiated integrity algorithm key.
- * @param decryptKey the negotiated decryption key.
+ * @param decryptionKey the negotiated decryption key.
* @return a pair including IkePayload and next payload type.
* @throws IkeProtocolException for decoding errors.
* @throws GeneralSecurityException if there is any error during integrity check or decryption.
@@ -145,7 +175,7 @@
IkeMacIntegrity integrityMac,
IkeCipher decryptCipher,
byte[] integrityKey,
- byte[] decryptKey)
+ byte[] decryptionKey)
throws IkeProtocolException, GeneralSecurityException {
ByteBuffer input =
ByteBuffer.wrap(
@@ -174,26 +204,15 @@
+ " or SK Payload is not the only payload.");
}
- IkeSkPayload payload = null;
- if (isSkf) {
- payload =
- new IkeSkfPayload(
- isCritical,
- message,
- integrityMac,
- decryptCipher,
- integrityKey,
- decryptKey);
- } else {
- payload =
- new IkeSkPayload(
- isCritical,
- message,
- integrityMac,
- decryptCipher,
- integrityKey,
- decryptKey);
- }
+ IkeSkPayload payload =
+ sDecoderInstance.decodeIkeSkPayload(
+ isSkf,
+ isCritical,
+ message,
+ integrityMac,
+ decryptCipher,
+ integrityKey,
+ decryptionKey);
return new Pair(payload, nextPayloadType);
}
@@ -209,5 +228,15 @@
IkePayload decodeIkePayload(
int payloadType, boolean isCritical, boolean isResp, byte[] payloadBody)
throws IkeProtocolException;
+
+ IkeSkPayload decodeIkeSkPayload(
+ boolean isSkf,
+ boolean critical,
+ byte[] message,
+ @Nullable IkeMacIntegrity integrityMac,
+ IkeCipher decryptCipher,
+ byte[] integrityKey,
+ byte[] decryptionKey)
+ throws IkeProtocolException, GeneralSecurityException;
}
}
diff --git a/src/java/com/android/ike/ikev2/message/IkeSkPayload.java b/src/java/com/android/ike/ikev2/message/IkeSkPayload.java
index 8a82936..aa780f9 100644
--- a/src/java/com/android/ike/ikev2/message/IkeSkPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeSkPayload.java
@@ -50,7 +50,7 @@
* @param integrityMac the negotiated integrity algorithm.
* @param decryptCipher the negotiated encryption algorithm.
* @param integrityKey the negotiated integrity algorithm key.
- * @param decryptKey the negotiated decryption key.
+ * @param decryptionKey the negotiated decryption key.
*/
@VisibleForTesting
IkeSkPayload(
@@ -59,7 +59,7 @@
@Nullable IkeMacIntegrity integrityMac,
IkeCipher decryptCipher,
byte[] integrityKey,
- byte[] decryptKey)
+ byte[] decryptionKey)
throws IkeProtocolException, GeneralSecurityException {
this(
@@ -70,7 +70,7 @@
integrityMac,
decryptCipher,
integrityKey,
- decryptKey);
+ decryptionKey);
}
/** Construct an instance of IkeSkPayload for testing.*/
@@ -89,7 +89,7 @@
@Nullable IkeMacIntegrity integrityMac,
IkeCipher decryptCipher,
byte[] integrityKey,
- byte[] decryptKey)
+ byte[] decryptionKey)
throws IkeProtocolException, GeneralSecurityException {
super(isSkf ? PAYLOAD_TYPE_SKF : PAYLOAD_TYPE_SK, critical);
@@ -102,7 +102,7 @@
integrityMac,
decryptCipher,
integrityKey,
- decryptKey);
+ decryptionKey);
}
/**
diff --git a/src/java/com/android/ike/ikev2/message/IkeSkfPayload.java b/src/java/com/android/ike/ikev2/message/IkeSkfPayload.java
index 93abe90..54f083f 100644
--- a/src/java/com/android/ike/ikev2/message/IkeSkfPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeSkfPayload.java
@@ -52,7 +52,7 @@
* @param integrityMac the negotiated integrity algorithm.
* @param decryptCipher the negotiated encryption algorithm.
* @param integrityKey the negotiated integrity algorithm key.
- * @param decryptKey the negotiated decryption key.
+ * @param decryptionKey the negotiated decryption key.
*/
IkeSkfPayload(
boolean critical,
@@ -60,7 +60,7 @@
@Nullable IkeMacIntegrity integrityMac,
IkeCipher decryptCipher,
byte[] integrityKey,
- byte[] decryptKey)
+ byte[] decryptionKey)
throws IkeProtocolException, GeneralSecurityException {
super(
true /*isSkf*/,
@@ -70,7 +70,7 @@
integrityMac,
decryptCipher,
integrityKey,
- decryptKey);
+ decryptionKey);
// TODO: Support constructing IkeEncryptedPayloadBody using AEAD.
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java
index f3941fb..5387a6f 100644
--- a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java
@@ -389,7 +389,8 @@
any(),
eq(ikeSaRecord),
eq(dummyIkeMessage.ikeHeader),
- eq(dummyIkePacketBytes)))
+ eq(dummyIkePacketBytes),
+ eq(null)))
.thenReturn(new DecodeResultOk(dummyIkeMessage));
return new ReceivedIkePacket(dummyIkeMessage.ikeHeader, dummyIkePacketBytes);
@@ -415,8 +416,9 @@
? ikeSaRecord.getLocalRequestMessageId()
: ikeSaRecord.getRemoteRequestMessageId());
when(mMockIkeMessageHelper.decode(
- anyInt(), any(), any(), eq(ikeSaRecord), eq(header), any()))
- .thenReturn(new DecodeResultError(DECODE_STATUS_PROTECTED_ERROR, exception));
+ anyInt(), any(), any(), eq(ikeSaRecord), eq(header), any(), any()))
+ .thenReturn(
+ new DecodeResultError(DECODE_STATUS_PROTECTED_ERROR, exception));
return new ReceivedIkePacket(header, new byte[0]);
}
@@ -462,7 +464,8 @@
any(),
eq(record),
eq(rcvPacket.ikeHeader),
- eq(rcvPacket.ikePacketBytes));
+ eq(rcvPacket.ikePacketBytes),
+ eq(null));
}
private static IkeSaRecord makeDummyIkeSaRecord(long initSpi, long respSpi, boolean isLocalInit)
@@ -1747,9 +1750,9 @@
boolean hasChildPayloads)
throws Exception {
// Send IKE AUTH response to IKE state machine
+ ReceivedIkePacket authResp = makeIkeAuthRespWithChildPayloads(authRelatedPayloads);
mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeIkeAuthRespWithChildPayloads(authRelatedPayloads));
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, authResp);
mLooper.dispatchAll();
// Validate outbound IKE AUTH request
@@ -1765,7 +1768,7 @@
// Validate inbound IKE AUTH response
verifyIncrementLocaReqMsgId();
- verify(mMockIkeMessageHelper).decode(anyInt(), any(), any(), any(), any(), any());
+ verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, authResp);
// Validate authentication is done. Cannot use matchers because IkeAuthPskPayload is final.
verify(spyAuthPayload)
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java
index 36efa3a..bce248f 100644
--- a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java
@@ -20,6 +20,7 @@
import static com.android.ike.ikev2.message.IkeMessage.DECODE_STATUS_PROTECTED_ERROR;
import static com.android.ike.ikev2.message.IkeMessage.DECODE_STATUS_UNPROTECTED_ERROR;
import static com.android.ike.ikev2.message.IkePayload.PAYLOAD_TYPE_AUTH;
+import static com.android.ike.ikev2.message.IkePayload.PAYLOAD_TYPE_ID_INITIATOR;
import static com.android.ike.ikev2.message.IkePayload.PAYLOAD_TYPE_NO_NEXT;
import static org.junit.Assert.assertArrayEquals;
@@ -29,7 +30,13 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import com.android.ike.TestUtils;
@@ -38,7 +45,6 @@
import com.android.ike.ikev2.crypto.IkeMacIntegrity;
import com.android.ike.ikev2.exceptions.IkeException;
import com.android.ike.ikev2.exceptions.IkeInternalException;
-import com.android.ike.ikev2.exceptions.IkeProtocolException;
import com.android.ike.ikev2.exceptions.InvalidMessageIdException;
import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import com.android.ike.ikev2.exceptions.UnsupportedCriticalPayloadException;
@@ -46,6 +52,7 @@
import com.android.ike.ikev2.message.IkeMessage.DecodeResultError;
import com.android.ike.ikev2.message.IkeMessage.DecodeResultOk;
import com.android.ike.ikev2.message.IkeMessage.DecodeResultPartial;
+import com.android.ike.ikev2.message.IkePayloadFactory.IIkePayloadDecoder;
import org.junit.After;
import org.junit.Before;
@@ -114,6 +121,18 @@
+ "29000008000040000000000c000040010000000100000000"
+ "000000000000000b";
+ private static final String IKE_FRAG_HEX_STRING =
+ "939ae1251d18eb9077a99551b15c6e9335202320000000010000"
+ + "00c0000000a400020002fd7c7931705af184b7be76bbd45a"
+ + "8ecbb3ffd58b9438b93f67e9fe86b06229f80e9b52d2ff6a"
+ + "fde3f2c13ae93ce55a801f62e1a818c9003880a36bbe986f"
+ + "e6979ba233b9f4f0ddc992d06dbad5a2b998be18fae947e5"
+ + "ccfb37775d069344e711fbf499bb289cf4cca245bd450ad8"
+ + "9d18689207759507ba18d47247e920b9e000a25a7596e413"
+ + "0929e5cdc37d5c1b0d90bbaae946c260f4d3cf815f6d";
+ private static final String ID_INIT_PAYLOAD_HEX_STRING = "2400000c010000000a50500d";
+ private static final String ID_RESP_PAYLOAD_HEX_STRING = "0000000c010000000a505050";
+
private static final long INIT_SPI = 0x5f54bf6d8b48e6e1L;
private static final long RESP_SPI = 0x909232b3d1edcb5cL;
private static final String IKE_EMPTY_INFO_MSG_HEX_STRING =
@@ -134,6 +153,10 @@
private static final int FRAGMENT_NUM_ONE = 1;
private static final int FRAGMENT_NUM_TWO = 2;
+ private static final int IKE_FRAG_EXPECTED_MESSAGE_ID = 1;
+ private static final int TOTAL_FRAGMENTS_OFFSET =
+ IkeHeader.IKE_HEADER_LENGTH + IkePayload.GENERIC_HEADER_LENGTH + 2;
+
private static final int IKE_AUTH_EXPECTED_MESSAGE_ID = 1;
private static final int IKE_AUTH_CIPHER_IV_SIZE = 16;
private static final int IKE_AUTH_CIPHER_BLOCK_SIZE = 16;
@@ -143,12 +166,15 @@
private byte[] mUnencryptedPaddedData;
private IkeHeader mIkeAuthHeader;
+ private IIkePayloadDecoder mSpyIkePayloadDecoder;
+
private IkeMacIntegrity mMockIntegrity;
private IkeCipher mMockCipher;
private IkeSaRecord mMockIkeSaRecord;
- private IkeHeader mMockFragOneHeader;
- private IkeHeader mMockFragTwoHeader;
+ private byte[] mIkeFragPacket;
+ private IkeHeader mFragOneHeader;
+ private IkeHeader mFragTwoHeader;
private IkeSkfPayload mDummySkfPayloadOne;
private IkeSkfPayload mDummySkfPayloadTwo;
@@ -187,20 +213,20 @@
@Before
public void setUp() throws Exception {
- IkePayloadFactory.sDecoderInstance =
- new IkePayloadFactory.IIkePayloadDecoder() {
-
- @Override
- public IkePayload decodeIkePayload(
- int payloadType, boolean isCritical, boolean isResp, byte[] payloadBody)
- throws IkeProtocolException {
- if (support(payloadType)) {
- return new TestIkeSupportedPayload(payloadType, isCritical);
- } else {
- return new IkeUnsupportedPayload(payloadType, isCritical);
- }
+ mSpyIkePayloadDecoder = spy(new IkePayloadFactory.IkePayloadDecoder());
+ doAnswer(
+ (invocation) -> {
+ int payloadType = (int) invocation.getArguments()[0];
+ boolean isCritical = (boolean) invocation.getArguments()[1];
+ if (support(payloadType)) {
+ return new TestIkeSupportedPayload(payloadType, isCritical);
}
- };
+ return new IkeUnsupportedPayload(payloadType, isCritical);
+ })
+ .when(mSpyIkePayloadDecoder)
+ .decodeIkePayload(anyInt(), anyBoolean(), anyBoolean(), any());
+
+ IkePayloadFactory.sDecoderInstance = mSpyIkePayloadDecoder;
mIkeAuthPacket = TestUtils.hexStringToByteArray(IKE_AUTH_HEX_STRING);
mUnencryptedPaddedData =
@@ -222,8 +248,9 @@
when(mMockIkeSaRecord.getInboundDecryptionKey()).thenReturn(new byte[0]);
when(mMockIkeSaRecord.getInboundIntegrityKey()).thenReturn(new byte[0]);
- mMockFragOneHeader = mock(IkeHeader.class);
- mMockFragTwoHeader = mock(IkeHeader.class);
+ mIkeFragPacket = TestUtils.hexStringToByteArray(IKE_FRAG_HEX_STRING);
+ mFragOneHeader = new IkeHeader(mIkeFragPacket);
+ mFragTwoHeader = new IkeHeader(mIkeFragPacket);
mDummySkfPayloadOne =
makeDummySkfPayload(
@@ -349,7 +376,8 @@
mMockCipher,
mMockIkeSaRecord,
mIkeAuthHeader,
- mIkeAuthPacket);
+ mIkeAuthPacket,
+ null /*collectedFragments*/);
IkeMessage ikeMessage = verifyDecodeResultOkAndGetMessage(decodeResult);
assertEquals(IKE_AUTH_PAYLOAD_SIZE, ikeMessage.ikePayloadList.size());
@@ -364,7 +392,8 @@
mMockCipher,
mMockIkeSaRecord,
mIkeAuthHeader,
- mIkeAuthPacket);
+ mIkeAuthPacket,
+ null /*collectedFragments*/);
IkeException ikeException =
verifyDecodeResultErrorAndGetIkeException(
decodeResult, DECODE_STATUS_UNPROTECTED_ERROR);
@@ -383,7 +412,8 @@
mMockCipher,
mMockIkeSaRecord,
mIkeAuthHeader,
- mIkeAuthPacket);
+ mIkeAuthPacket,
+ null /*collectedFragments*/);
IkeException ikeException =
verifyDecodeResultErrorAndGetIkeException(
decodeResult, DECODE_STATUS_UNPROTECTED_ERROR);
@@ -404,7 +434,9 @@
mMockCipher,
mMockIkeSaRecord,
mIkeAuthHeader,
- mIkeAuthPacket);
+ mIkeAuthPacket,
+ null /*collectedFragments*/);
+
IkeException ikeException =
verifyDecodeResultErrorAndGetIkeException(
decodeResult, DECODE_STATUS_UNPROTECTED_ERROR);
@@ -429,7 +461,8 @@
mMockCipher,
mMockIkeSaRecord,
mIkeAuthHeader,
- mIkeAuthPacket);
+ mIkeAuthPacket,
+ null /*collectedFragments*/);
IkeException ikeException =
verifyDecodeResultErrorAndGetIkeException(
decodeResult, DECODE_STATUS_PROTECTED_ERROR);
@@ -487,19 +520,20 @@
private DecodeResultPartial makeDecodeResultForFragOne(DecodeResultPartial collectedFrags) {
return new DecodeResultPartial(
- mMockFragOneHeader, mDummySkfPayloadOne, PAYLOAD_TYPE_AUTH, collectedFrags);
+ mFragOneHeader, mDummySkfPayloadOne, PAYLOAD_TYPE_AUTH, collectedFrags);
}
private DecodeResultPartial makeDecodeResultForFragTwo(DecodeResultPartial collectedFrags) {
return new DecodeResultPartial(
- mMockFragTwoHeader, mDummySkfPayloadTwo, PAYLOAD_TYPE_NO_NEXT, collectedFrags);
+ mFragTwoHeader, mDummySkfPayloadTwo, PAYLOAD_TYPE_NO_NEXT, collectedFrags);
}
@Test
public void testConstructDecodePartialFirstFragArriveFirst() throws Exception {
DecodeResultPartial resultPartial = makeDecodeResultForFragOne(null /*collectedFragments*/);
- assertEquals(mMockFragOneHeader, resultPartial.ikeHeader);
+ assertEquals(PAYLOAD_TYPE_AUTH, resultPartial.firstPayloadType);
+ assertEquals(mFragOneHeader, resultPartial.ikeHeader);
assertEquals(TOTAL_FRAGMENTS, resultPartial.collectedFragsList.length);
assertArrayEquals(
@@ -513,7 +547,7 @@
DecodeResultPartial resultPartial = makeDecodeResultForFragTwo(null /*collectedFragments*/);
assertEquals(PAYLOAD_TYPE_NO_NEXT, resultPartial.firstPayloadType);
- assertEquals(mMockFragTwoHeader, resultPartial.ikeHeader);
+ assertEquals(mFragTwoHeader, resultPartial.ikeHeader);
assertEquals(TOTAL_FRAGMENTS, resultPartial.collectedFragsList.length);
assertArrayEquals(
@@ -530,7 +564,7 @@
makeDecodeResultForFragOne(resultPartialIncomplete);
assertEquals(PAYLOAD_TYPE_AUTH, resultPartialComplete.firstPayloadType);
- assertEquals(mMockFragTwoHeader, resultPartialComplete.ikeHeader);
+ assertEquals(mFragTwoHeader, resultPartialComplete.ikeHeader);
assertEquals(TOTAL_FRAGMENTS, resultPartialComplete.collectedFragsList.length);
assertTrue(resultPartialComplete.isAllFragmentsReceived());
@@ -544,11 +578,12 @@
makeDecodeResultForFragTwo(resultPartialIncomplete);
assertEquals(PAYLOAD_TYPE_AUTH, resultPartialIncomplete.firstPayloadType);
- assertEquals(mMockFragOneHeader, resultPartialIncomplete.ikeHeader);
+ assertEquals(mFragOneHeader, resultPartialIncomplete.ikeHeader);
assertEquals(TOTAL_FRAGMENTS, resultPartialIncomplete.collectedFragsList.length);
assertTrue(resultPartialIncomplete.isAllFragmentsReceived());
+
// Verify reassembly result
ByteBuffer expectedBuffer =
ByteBuffer.allocate(
@@ -573,4 +608,217 @@
}
}
+
+ private void setDecryptSkfPayload(IkeSkfPayload skf) throws Exception {
+ doReturn(skf)
+ .when(mSpyIkePayloadDecoder)
+ .decodeIkeSkPayload(
+ eq(true),
+ anyBoolean(),
+ any(),
+ eq(mMockIntegrity),
+ eq(mMockCipher),
+ any(),
+ any());
+ }
+
+ private DecodeResult decodeSkf(
+ int expectedMsgId,
+ IkeHeader header,
+ byte[] packet,
+ DecodeResultPartial collectFragments)
+ throws Exception {
+ return IkeMessage.decode(
+ expectedMsgId,
+ mMockIntegrity,
+ mMockCipher,
+ mMockIkeSaRecord,
+ header,
+ packet,
+ collectFragments);
+ }
+
+ @Test
+ public void testRcvFirstArrivedFrag() throws Exception {
+ setDecryptSkfPayload(mDummySkfPayloadTwo);
+ DecodeResult decodeResult =
+ decodeSkf(
+ IKE_FRAG_EXPECTED_MESSAGE_ID,
+ mFragTwoHeader,
+ mIkeFragPacket,
+ null /* collectedFragments*/);
+
+ // Verify decoding result
+ assertTrue(decodeResult instanceof DecodeResultPartial);
+ DecodeResultPartial resultPartial = (DecodeResultPartial) decodeResult;
+
+ assertEquals(PAYLOAD_TYPE_NO_NEXT, resultPartial.firstPayloadType);
+ assertEquals(mFragTwoHeader, resultPartial.ikeHeader);
+
+ assertEquals(TOTAL_FRAGMENTS, resultPartial.collectedFragsList.length);
+ assertArrayEquals(
+ FRAGMENT_TWO_UNENCRYPTED_DATA,
+ resultPartial.collectedFragsList[FRAGMENT_NUM_TWO - 1]);
+ assertFalse(resultPartial.isAllFragmentsReceived());
+ }
+
+ @Test
+ public void testRcvLastArrivedFrag() throws Exception {
+ // Create two dummy SKF Payloads so that the complete unencrypted data is two ID payloads
+ byte[] idInitPayloadBytes = TestUtils.hexStringToByteArray(ID_INIT_PAYLOAD_HEX_STRING);
+ byte[] idRespPayloadBytes = TestUtils.hexStringToByteArray(ID_RESP_PAYLOAD_HEX_STRING);
+ IkeSkfPayload skfOne =
+ makeDummySkfPayload(idInitPayloadBytes, FRAGMENT_NUM_ONE, TOTAL_FRAGMENTS);
+ IkeSkfPayload skfTwo =
+ makeDummySkfPayload(idRespPayloadBytes, FRAGMENT_NUM_TWO, TOTAL_FRAGMENTS);
+
+ DecodeResultPartial resultPartialIncomplete =
+ new DecodeResultPartial(
+ mFragOneHeader,
+ skfOne,
+ PAYLOAD_TYPE_ID_INITIATOR,
+ null /* collectedFragments*/);
+
+ setDecryptSkfPayload(skfTwo);
+ DecodeResult decodeResult =
+ decodeSkf(
+ IKE_FRAG_EXPECTED_MESSAGE_ID,
+ mFragTwoHeader,
+ mIkeFragPacket,
+ resultPartialIncomplete);
+
+ // Verify fragments reassembly has been finished and complete message has been decoded.
+ assertTrue(decodeResult instanceof DecodeResultOk);
+ DecodeResultOk resultOk = (DecodeResultOk) decodeResult;
+ assertEquals(2, resultOk.ikeMessage.ikePayloadList.size());
+ }
+
+ @Test
+ public void testRcvFirstArrivedFragWithUnprotectedError() throws Exception {
+ DecodeResult decodeResult =
+ decodeSkf(
+ IKE_FRAG_EXPECTED_MESSAGE_ID + 1,
+ mFragTwoHeader,
+ mIkeFragPacket,
+ null /* collectedFragments*/);
+
+ // Verify that unprotected error was returned
+ IkeException ikeException =
+ verifyDecodeResultErrorAndGetIkeException(
+ decodeResult, DECODE_STATUS_UNPROTECTED_ERROR);
+ assertTrue(ikeException instanceof InvalidMessageIdException);
+ }
+
+ @Test
+ public void testRcvLastArrivedFragWithUnprotectedError() throws Exception {
+ DecodeResultPartial resultPartialIncomplete =
+ makeDecodeResultForFragOne(null /* collectedFragments*/);
+
+ DecodeResult decodeResult =
+ decodeSkf(
+ IKE_FRAG_EXPECTED_MESSAGE_ID + 1,
+ mFragTwoHeader,
+ mIkeFragPacket,
+ resultPartialIncomplete);
+
+ // Verify that newly received fragment was discarded
+ assertEquals(resultPartialIncomplete, decodeResult);
+ }
+
+ @Test
+ public void testRcvFragWithLargerTotalFragments() throws Exception {
+ DecodeResultPartial resultPartialIncomplete =
+ new DecodeResultPartial(
+ mFragOneHeader,
+ mDummySkfPayloadOne,
+ PAYLOAD_TYPE_NO_NEXT,
+ null /* collectedFragments*/);
+
+ // Set total fragments of inbound fragment to 5
+ int totalFragments = 5;
+ byte[] fragPacket = TestUtils.hexStringToByteArray(IKE_FRAG_HEX_STRING);
+ fragPacket[TOTAL_FRAGMENTS_OFFSET] = 0;
+ fragPacket[TOTAL_FRAGMENTS_OFFSET] = 5;
+
+ byte[] unencryptedData = "testRcvFragWithLargerTotalFragments".getBytes();
+ IkeSkfPayload skfPayload =
+ makeDummySkfPayload(unencryptedData, FRAGMENT_NUM_TWO, totalFragments);
+ setDecryptSkfPayload(skfPayload);
+ DecodeResult decodeResult =
+ decodeSkf(
+ IKE_FRAG_EXPECTED_MESSAGE_ID,
+ mFragTwoHeader,
+ fragPacket,
+ resultPartialIncomplete);
+
+ // Verify that previously collected fragments were all discarded
+ assertTrue(decodeResult instanceof DecodeResultPartial);
+ DecodeResultPartial resultPartial = (DecodeResultPartial) decodeResult;
+
+ assertEquals(PAYLOAD_TYPE_NO_NEXT, resultPartial.firstPayloadType);
+ assertEquals(mFragTwoHeader, resultPartial.ikeHeader);
+
+ assertEquals(totalFragments, resultPartial.collectedFragsList.length);
+ assertArrayEquals(unencryptedData, resultPartial.collectedFragsList[FRAGMENT_NUM_TWO - 1]);
+ assertFalse(resultPartial.isAllFragmentsReceived());
+ }
+
+ @Test
+ public void testRcvFragWithSmallerTotalFragments() throws Exception {
+ int totalFragments = 5;
+ byte[] unencryptedData = "testRcvFragWithSmallerTotalFragments".getBytes();
+ IkeSkfPayload skfPayload =
+ makeDummySkfPayload(unencryptedData, FRAGMENT_NUM_ONE, totalFragments);
+
+ DecodeResultPartial resultPartialIncomplete =
+ new DecodeResultPartial(
+ mFragOneHeader,
+ skfPayload,
+ PAYLOAD_TYPE_AUTH,
+ null /* collectedFragments*/);
+
+ setDecryptSkfPayload(mDummySkfPayloadTwo);
+ DecodeResult decodeResult =
+ decodeSkf(
+ IKE_FRAG_EXPECTED_MESSAGE_ID,
+ mFragTwoHeader,
+ mIkeFragPacket,
+ resultPartialIncomplete);
+
+ // Verify that newly received fragment was discarded
+ assertEquals(resultPartialIncomplete, decodeResult);
+ }
+
+ @Test
+ public void testRcvReplayFrag() throws Exception {
+ DecodeResultPartial resultPartialIncomplete =
+ makeDecodeResultForFragTwo(null /* collectedFragments*/);
+
+ setDecryptSkfPayload(mDummySkfPayloadTwo);
+ DecodeResult decodeResult =
+ decodeSkf(
+ IKE_FRAG_EXPECTED_MESSAGE_ID,
+ mFragTwoHeader,
+ mIkeFragPacket,
+ resultPartialIncomplete);
+
+ // Verify that newly received fragment was discarded
+ assertEquals(resultPartialIncomplete, decodeResult);
+ }
+
+ @Test
+ public void testRcvCompleteMessageDuringReassembly() throws Exception {
+ DecodeResultPartial resultPartialIncomplete =
+ makeDecodeResultForFragTwo(null /* collectedFragments*/);
+
+ DecodeResult decodeResult =
+ decodeSkf(
+ IKE_AUTH_EXPECTED_MESSAGE_ID,
+ mIkeAuthHeader,
+ mIkeAuthPacket,
+ resultPartialIncomplete);
+
+ // Verify that newly received IKE message was discarded
+ assertEquals(resultPartialIncomplete, decodeResult);
+ }
}
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkPayloadTest.java
index 26f3d01..f3af5b6 100644
--- a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkPayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkPayloadTest.java
@@ -63,7 +63,7 @@
private static final int CHECKSUM_LEN = 12;
private IkeCipher mAesCbcDecryptCipher;
- private byte[] mAesCbcDecryptKey;
+ private byte[] mAesCbcDecryptionKey;
private IkeMacIntegrity mHmacSha1IntegrityMac;
private byte[] mHmacSha1IntegrityKey;
@@ -76,7 +76,7 @@
SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
SaProposal.KEY_LEN_AES_128),
IkeMessage.getSecurityProvider());
- mAesCbcDecryptKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP);
+ mAesCbcDecryptionKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP);
mHmacSha1IntegrityMac =
IkeMacIntegrity.create(
new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96),
@@ -97,7 +97,7 @@
mHmacSha1IntegrityMac,
mAesCbcDecryptCipher,
mHmacSha1IntegrityKey,
- mAesCbcDecryptKey)
+ mAesCbcDecryptionKey)
.first;
int payloadLength = payload.getPayloadLength();
ByteBuffer buffer = ByteBuffer.allocate(payloadLength);
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkfPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkfPayloadTest.java
index e4c25d3..20c464b 100644
--- a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkfPayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkfPayloadTest.java
@@ -111,7 +111,7 @@
mSpyHmacSha256IntegrityMac,
mSpyAesCbcCipher,
new byte[0] /*integrityKey*/,
- new byte[0] /*decryptKey*/)
+ new byte[0] /*decryptionKey*/)
.first;
return payload;
}