aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorevitayan <evitayan@google.com>2020-03-23 20:49:03 -0700
committerevitayan <evitayan@google.com>2020-03-27 18:58:20 -0700
commit103072a7587c271a3eddbc1868f1b08268bab161 (patch)
tree503d9f5844aea4467b1e01e65c78b734474145e1
parent718fba970c258ad4dbe7ba2112a5c044fc5b013f (diff)
downloadike-103072a7587c271a3eddbc1868f1b08268bab161.tar.gz
Terminate IKE SA when hard lifetime alarm fires
Bug: 147831323 Test: atest FrameworksIkeTests Test: Manually test against Strongswan IKE server Change-Id: I028846d5af8c198a804e07da2623bb2d68905778
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java48
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/SaRecord.java118
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java4
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/SaRecordTest.java4
4 files changed, 155 insertions, 19 deletions
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 68133614..c64e83b7 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
+++ b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
@@ -90,6 +90,7 @@ import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalReq
import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.IkeLocalRequest;
import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
+import com.android.internal.net.ipsec.ike.SaRecord.SaLifetimeAlarmScheduler;
import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
@@ -1235,6 +1236,28 @@ public class IkeSessionStateMachine extends AbstractSessionStateMachine {
return obtainMessage(CMD_ALARM_FIRED, mIkeSessionId, localRequestType, spiBundle);
}
+ private SaLifetimeAlarmScheduler buildSaLifetimeAlarmScheduler(long remoteSpi) {
+ PendingIntent deleteSaIntent =
+ buildIkeAlarmIntent(
+ mContext,
+ ACTION_DELETE_IKE,
+ getIntentIdentifier(remoteSpi),
+ getIntentIkeSmMsg(CMD_LOCAL_REQUEST_DELETE_IKE, remoteSpi));
+ PendingIntent rekeySaIntent =
+ buildIkeAlarmIntent(
+ mContext,
+ ACTION_REKEY_IKE,
+ getIntentIdentifier(remoteSpi),
+ getIntentIkeSmMsg(CMD_LOCAL_REQUEST_REKEY_IKE, remoteSpi));
+
+ return new SaLifetimeAlarmScheduler(
+ mIkeSessionParams.getHardLifetimeMsInternal(),
+ mIkeSessionParams.getSoftLifetimeMsInternal(),
+ deleteSaIntent,
+ rekeySaIntent,
+ mAlarmManager);
+ }
+
// Package private. Accessible to ChildSessionStateMachine
static PendingIntent buildIkeAlarmIntent(
Context context, String intentAction, String intentId, Message ikeSmMsg) {
@@ -1479,12 +1502,13 @@ public class IkeSessionStateMachine extends AbstractSessionStateMachine {
protected void handleFiredAlarm(Message message) {
switch (message.arg2) {
+ case CMD_LOCAL_REQUEST_DELETE_IKE:
+ // IKE SA hits its hard lifetime
+ enqueueIkeLocalRequest(message);
+ return;
case CMD_LOCAL_REQUEST_DPD:
// IKE Session has not received any protectd IKE packet for the whole DPD delay
- long remoteIkeSpi = ((Bundle) message.obj).getLong(BUNDLE_KEY_IKE_REMOTE_SPI);
- sendMessage(
- CMD_LOCAL_REQUEST_DPD,
- new IkeLocalRequest(CMD_LOCAL_REQUEST_DPD, remoteIkeSpi));
+ enqueueIkeLocalRequest(message);
// TODO(b/152442041): Cancel the scheduled DPD request if IKE Session starts any
// procedure before DPD get executed.
@@ -1494,6 +1518,11 @@ public class IkeSessionStateMachine extends AbstractSessionStateMachine {
}
// TODO: Handle delete and rekey IKE/Child SA
}
+
+ private void enqueueIkeLocalRequest(Message message) {
+ long remoteIkeSpi = ((Bundle) message.obj).getLong(BUNDLE_KEY_IKE_REMOTE_SPI);
+ sendMessage(message.arg2, new IkeLocalRequest(message.arg2, remoteIkeSpi));
+ }
}
/**
@@ -2660,7 +2689,8 @@ public class IkeSessionStateMachine extends AbstractSessionStateMachine {
mIkePrf,
mIkeIntegrity == null ? 0 : mIkeIntegrity.getKeyLength(),
mIkeCipher.getKeyLength(),
- new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
+ new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE),
+ buildSaLifetimeAlarmScheduler(mRemoteIkeSpiResource.getSpi()));
addIkeSaRecord(mCurrentIkeSaRecord);
ikeInitSuccess = true;
@@ -3805,6 +3835,10 @@ public class IkeSessionStateMachine extends AbstractSessionStateMachine {
newPrf = IkeMacPrf.create(respProposal.saProposal.getPrfTransforms()[0]);
// Build new SaRecord
+ long remoteSpi =
+ isLocalInit
+ ? respProposal.getIkeSpiResource().getSpi()
+ : reqProposal.getIkeSpiResource().getSpi();
IkeSaRecord newSaRecord =
IkeSaRecord.makeRekeyedIkeSaRecord(
mCurrentIkeSaRecord,
@@ -3817,8 +3851,8 @@ public class IkeSessionStateMachine extends AbstractSessionStateMachine {
newIntegrity == null ? 0 : newIntegrity.getKeyLength(),
newCipher.getKeyLength(),
isLocalInit,
- new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
-
+ new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE),
+ buildSaLifetimeAlarmScheduler(remoteSpi));
addIkeSaRecord(newSaRecord);
mIkeCipher = newCipher;
diff --git a/src/java/com/android/internal/net/ipsec/ike/SaRecord.java b/src/java/com/android/internal/net/ipsec/ike/SaRecord.java
index ca8f4757..25cc740c 100644
--- a/src/java/com/android/internal/net/ipsec/ike/SaRecord.java
+++ b/src/java/com/android/internal/net/ipsec/ike/SaRecord.java
@@ -18,6 +18,8 @@ package com.android.internal.net.ipsec.ike;
import static android.net.ipsec.ike.IkeManager.getIkeLog;
import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.content.Context;
import android.net.IpSecManager;
import android.net.IpSecManager.ResourceUnavailableException;
@@ -25,6 +27,7 @@ import android.net.IpSecManager.SecurityParameterIndex;
import android.net.IpSecManager.SpiUnavailableException;
import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.IpSecTransform;
+import android.os.SystemClock;
import android.util.CloseGuard;
import com.android.internal.annotations.VisibleForTesting;
@@ -79,6 +82,9 @@ public abstract class SaRecord implements AutoCloseable {
private final byte[] mSkEi;
private final byte[] mSkEr;
+ private final SaLifetimeAlarmScheduler mSaLifetimeAlarmScheduler;
+
+ // TODO(b/149058810): Use AlarmManager and PendingIntent to schedule rekey
private final LocalRequest mFutureRekeyEvent;
private final CloseGuard mCloseGuard = new CloseGuard();
@@ -92,7 +98,8 @@ public abstract class SaRecord implements AutoCloseable {
byte[] skAr,
byte[] skEi,
byte[] skEr,
- LocalRequest futureRekeyEvent) {
+ LocalRequest futureRekeyEvent,
+ SaLifetimeAlarmScheduler saLifetimeAlarmScheduler) {
isLocalInit = localInit;
nonceInitiator = nonceInit;
nonceResponder = nonceResp;
@@ -107,6 +114,15 @@ public abstract class SaRecord implements AutoCloseable {
logKey("SK_ei", skEi);
logKey("SK_er", skEr);
+ mSaLifetimeAlarmScheduler = saLifetimeAlarmScheduler;
+
+ // TODO(b/147831323): Remove this condition check after we pass in a real
+ // saLifetimeAlarmScheduler to ChildSaRecord
+ if (mSaLifetimeAlarmScheduler != null) {
+ mSaLifetimeAlarmScheduler.scheduleLifetimeExpiryAlarm(getTag());
+ }
+
+ // TODO(b/149058810): Use alarmManager to schedule rekey event and remove mFutureRekeyEvent
mFutureRekeyEvent = futureRekeyEvent;
mCloseGuard.open("close");
@@ -168,6 +184,12 @@ public abstract class SaRecord implements AutoCloseable {
@Override
public void close() {
mFutureRekeyEvent.cancel();
+
+ // TODO(b/147831323): Remove this condition check after we pass in a real
+ // saLifetimeAlarmScheduler to ChildSaRecord
+ if (mSaLifetimeAlarmScheduler != null) {
+ mSaLifetimeAlarmScheduler.cancelLifetimeExpiryAlarm(getTag());
+ }
}
/** Package private */
@@ -323,7 +345,8 @@ public abstract class SaRecord implements AutoCloseable {
skEr,
skPi,
skPr,
- ikeSaRecordConfig.futureRekeyEvent);
+ ikeSaRecordConfig.futureRekeyEvent,
+ ikeSaRecordConfig.saLifetimeAlarmScheduler);
}
@Override
@@ -514,6 +537,52 @@ public abstract class SaRecord implements AutoCloseable {
}
}
+ /** This class provides methods to schedule and cancel SA lifetime expiry alarm */
+ static class SaLifetimeAlarmScheduler {
+ private final long mDeleteDelayMs;
+ private final long mRekeyDelayMs;
+ private final PendingIntent mDeleteSaIntent;
+ private final PendingIntent mRekeySaIntent;
+ private final AlarmManager mAlarmManager;
+
+ SaLifetimeAlarmScheduler(
+ long deleteDelayMs,
+ long rekeyDelayMs,
+ PendingIntent deleteSaIntent,
+ PendingIntent rekeySaIntent,
+ AlarmManager alarmManager) {
+ mDeleteDelayMs = deleteDelayMs;
+ mRekeyDelayMs = rekeyDelayMs;
+ mAlarmManager = alarmManager;
+ mDeleteSaIntent = deleteSaIntent;
+ mRekeySaIntent = rekeySaIntent;
+ }
+
+ public void scheduleLifetimeExpiryAlarm(String tag) {
+ // Hard lifetime expiry alarm needs to be "setExact" considering the hard lifetime
+ // minimum value is 5 minutes and the inexact alarm might cause at most 75% of the
+ // scheduled interval delay because batching alarms. It is not necessay to wake up the
+ // alarm during doze mode because even the SA expires at that time, the device can not
+ // get access to network and won't expose more vulnerabilities.
+ mAlarmManager.setExact(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + mDeleteDelayMs,
+ mDeleteSaIntent);
+ getIkeLog().d(tag, "Hard lifetime expiry alarm set for " + mDeleteDelayMs + "ms");
+
+ // TODO: Schedule alarm for rekey
+ }
+
+ public void cancelLifetimeExpiryAlarm(String tag) {
+ mAlarmManager.cancel(mDeleteSaIntent);
+ mAlarmManager.cancel(mRekeySaIntent);
+ mDeleteSaIntent.cancel();
+ mRekeySaIntent.cancel();
+
+ getIkeLog().d(tag, "Hard and soft lifetime alarm cancelled");
+ }
+ }
+
/** Package private class to group parameters for building a ChildSaRecord. */
@VisibleForTesting
static final class ChildSaRecordConfig {
@@ -599,8 +668,18 @@ public abstract class SaRecord implements AutoCloseable {
byte[] skEr,
byte[] skPi,
byte[] skPr,
- LocalRequest futureRekeyEvent) {
- super(localInit, nonceInit, nonceResp, skAi, skAr, skEi, skEr, futureRekeyEvent);
+ LocalRequest futureRekeyEvent,
+ SaLifetimeAlarmScheduler saLifetimeAlarmScheduler) {
+ super(
+ localInit,
+ nonceInit,
+ nonceResp,
+ skAi,
+ skAr,
+ skEi,
+ skEr,
+ futureRekeyEvent,
+ saLifetimeAlarmScheduler);
mInitiatorSpiResource = initSpi;
mResponderSpiResource = respSpi;
@@ -632,7 +711,8 @@ public abstract class SaRecord implements AutoCloseable {
IkeMacPrf prf,
int integrityKeyLength,
int encryptionKeyLength,
- LocalRequest futureRekeyEvent)
+ LocalRequest futureRekeyEvent,
+ SaLifetimeAlarmScheduler saLifetimeAlarmScheduler)
throws GeneralSecurityException {
return sSaRecordHelper.makeFirstIkeSaRecord(
initRequest,
@@ -644,7 +724,8 @@ public abstract class SaRecord implements AutoCloseable {
integrityKeyLength,
encryptionKeyLength,
true /*isLocalInit*/,
- futureRekeyEvent));
+ futureRekeyEvent,
+ saLifetimeAlarmScheduler));
}
/** Package private */
@@ -659,7 +740,8 @@ public abstract class SaRecord implements AutoCloseable {
int integrityKeyLength,
int encryptionKeyLength,
boolean isLocalInit,
- LocalRequest futureRekeyEvent)
+ LocalRequest futureRekeyEvent,
+ SaLifetimeAlarmScheduler saLifetimeAlarmScheduler)
throws GeneralSecurityException {
return sSaRecordHelper.makeRekeyedIkeSaRecord(
oldSaRecord,
@@ -673,7 +755,8 @@ public abstract class SaRecord implements AutoCloseable {
integrityKeyLength,
encryptionKeyLength,
isLocalInit,
- futureRekeyEvent));
+ futureRekeyEvent,
+ saLifetimeAlarmScheduler));
}
private void logKey(String type, byte[] key) {
@@ -852,6 +935,7 @@ public abstract class SaRecord implements AutoCloseable {
public final int encryptionKeyLength;
public final boolean isLocalInit;
public final LocalRequest futureRekeyEvent;
+ public final SaLifetimeAlarmScheduler saLifetimeAlarmScheduler;
IkeSaRecordConfig(
IkeSecurityParameterIndex initSpi,
@@ -860,7 +944,8 @@ public abstract class SaRecord implements AutoCloseable {
int integrityKeyLength,
int encryptionKeyLength,
boolean isLocalInit,
- LocalRequest futureRekeyEvent) {
+ LocalRequest futureRekeyEvent,
+ SaLifetimeAlarmScheduler saLifetimeAlarmScheduler) {
this.initSpi = initSpi;
this.respSpi = respSpi;
this.prf = prf;
@@ -868,6 +953,7 @@ public abstract class SaRecord implements AutoCloseable {
this.encryptionKeyLength = encryptionKeyLength;
this.isLocalInit = isLocalInit;
this.futureRekeyEvent = futureRekeyEvent;
+ this.saLifetimeAlarmScheduler = saLifetimeAlarmScheduler;
}
}
@@ -899,7 +985,19 @@ public abstract class SaRecord implements AutoCloseable {
IpSecTransform inTransform,
IpSecTransform outTransform,
ChildLocalRequest futureRekeyEvent) {
- super(localInit, nonceInit, nonceResp, skAi, skAr, skEi, skEr, futureRekeyEvent);
+ super(
+ localInit,
+ nonceInit,
+ nonceResp,
+ skAi,
+ skAr,
+ skEi,
+ skEr,
+ futureRekeyEvent,
+ null /*saLifetimeAlarmScheduler*/);
+
+ // TODO(b/147831323): Build a saLifetimeAlarmScheduler in ChildSessionStateMachine and
+ // pass it to ChildSaRecord
mInboundSpi = inSpi;
mOutboundSpi = outSpi;
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 119cf2ab..5f25cbae 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
@@ -107,6 +107,7 @@ import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.ReceivedIkePack
import com.android.internal.net.ipsec.ike.SaRecord.ISaRecordHelper;
import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecordConfig;
+import com.android.internal.net.ipsec.ike.SaRecord.SaLifetimeAlarmScheduler;
import com.android.internal.net.ipsec.ike.SaRecord.SaRecordHelper;
import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
@@ -638,7 +639,8 @@ public final class IkeSessionStateMachineTest {
new byte[KEY_LEN_IKE_ENCR],
TestUtils.hexStringToByteArray(PRF_KEY_INIT_HEX_STRING),
TestUtils.hexStringToByteArray(PRF_KEY_RESP_HEX_STRING),
- new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
+ new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE),
+ mock(SaLifetimeAlarmScheduler.class));
}
@Before
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 869c5636..97704701 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
@@ -45,6 +45,7 @@ import com.android.internal.net.ipsec.ike.SaRecord.IIpSecTransformHelper;
import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecordConfig;
import com.android.internal.net.ipsec.ike.SaRecord.IpSecTransformHelper;
+import com.android.internal.net.ipsec.ike.SaRecord.SaLifetimeAlarmScheduler;
import com.android.internal.net.ipsec.ike.SaRecord.SaRecordHelper;
import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
@@ -184,7 +185,8 @@ public final class SaRecordTest {
IKE_AUTH_ALGO_KEY_LEN,
IKE_ENCR_ALGO_KEY_LEN,
true /*isLocalInit*/,
- mMockFutureRekeyIkeEvent);
+ mMockFutureRekeyIkeEvent,
+ mock(SaLifetimeAlarmScheduler.class));
int keyMaterialLen =
IKE_SK_D_KEY_LEN