diff options
author | evitayan <evitayan@google.com> | 2020-03-23 20:49:03 -0700 |
---|---|---|
committer | evitayan <evitayan@google.com> | 2020-03-27 18:58:20 -0700 |
commit | 103072a7587c271a3eddbc1868f1b08268bab161 (patch) | |
tree | 503d9f5844aea4467b1e01e65c78b734474145e1 | |
parent | 718fba970c258ad4dbe7ba2112a5c044fc5b013f (diff) | |
download | ike-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
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 |