diff options
author | Cody Kesting <ckesting@google.com> | 2019-10-31 09:54:43 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-10-31 09:54:43 -0700 |
commit | 8c0c0644902af46e3f2d5223dcb4b660df4d686f (patch) | |
tree | edbf1bcfde6b3208bdfc08b5386024f69e8facbf | |
parent | ec24f3aa36139ef2fe7838583c898e50010b670d (diff) | |
parent | 47f189aa4d6568f731d13f47c074a487634209c3 (diff) | |
download | ike-8c0c0644902af46e3f2d5223dcb4b660df4d686f.tar.gz |
Override key generation for EAP-AKA'.
am: 47f189aa4d
Change-Id: I245d969a79b8402ed66a08c304f38a88b73897e2
3 files changed, 139 insertions, 0 deletions
diff --git a/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachine.java b/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachine.java index f047cf6f..b70c3f71 100644 --- a/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachine.java +++ b/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachine.java @@ -19,13 +19,17 @@ package com.android.ike.eap.statemachine; import static com.android.ike.eap.EapAuthenticator.LOG; import static com.android.ike.eap.message.EapData.EAP_TYPE_AKA_PRIME; import static com.android.ike.eap.message.simaka.EapAkaTypeData.EAP_AKA_CLIENT_ERROR; +import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN; import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF; import static com.android.ike.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF_INPUT; +import android.annotation.Nullable; import android.content.Context; +import com.android.ike.crypto.KeyGenerationUtils; import com.android.ike.eap.EapResult; import com.android.ike.eap.EapSessionConfig.EapAkaPrimeConfig; +import com.android.ike.eap.crypto.HmacSha256ByteSigner; import com.android.ike.eap.message.EapData.EapMethod; import com.android.ike.eap.message.EapMessage; import com.android.ike.eap.message.simaka.EapAkaPrimeTypeData; @@ -39,6 +43,8 @@ import com.android.ike.eap.message.simaka.EapSimAkaAttribute.AtKdfInput; import com.android.ike.eap.message.simaka.EapSimAkaTypeData.DecodeResult; import com.android.internal.annotations.VisibleForTesting; +import java.nio.BufferOverflowException; +import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; @@ -71,12 +77,22 @@ import javax.crypto.spec.SecretKeySpec; * Protocol Method for 3rd Generation Authentication and Key Agreement (EAP-AKA')</a> */ public class EapAkaPrimeMethodStateMachine extends EapAkaMethodStateMachine { + public static final int K_AUT_LEN = 32; + public static final int K_RE_LEN = 32; + // EAP-AKA' identity prefix (RFC 5448#3) private static final String AKA_PRIME_IDENTITY_PREFIX = "6"; private static final int SUPPORTED_KDF = 1; private static final int FC = 0x20; // Required by TS 133 402 Annex A.2 private static final int SQN_XOR_AK_LEN = 6; private static final String MAC_ALGORITHM_STRING = "HmacSHA256"; + private static final String MK_DATA_PREFIX = "EAP-AKA'"; + + // MK_LEN_BYTES = len(K_encr | K_aut | K_re | MSK | EMSK) + private static final int MK_LEN_BYTES = + KEY_LEN + K_AUT_LEN + K_RE_LEN + (2 * SESSION_KEY_LENGTH); + + public final byte[] mKRe = new byte[getKReLen()]; private final EapAkaPrimeConfig mEapAkaPrimeConfig; private final EapAkaPrimeTypeDataDecoder mEapAkaPrimeTypeDataDecoder; @@ -110,6 +126,15 @@ public class EapAkaPrimeMethodStateMachine extends EapAkaMethodStateMachine { } @Override + protected int getKAutLength() { + return K_AUT_LEN; + } + + protected int getKReLen() { + return K_RE_LEN; + } + + @Override protected DecodeResult<EapAkaTypeData> decode(byte[] typeData) { return mEapAkaPrimeTypeDataDecoder.decode(typeData); } @@ -213,6 +238,51 @@ public class EapAkaPrimeMethodStateMachine extends EapAkaMethodStateMachine { return true; } + @Nullable + @Override + protected EapResult generateAndPersistEapAkaKeys( + RandChallengeResult result, int eapIdentifier, EapAkaTypeData eapAkaTypeData) { + try { + AtKdfInput atKdfInput = + (AtKdfInput) eapAkaTypeData.attributeMap.get(EAP_AT_KDF_INPUT); + AtAutn atAutn = (AtAutn) eapAkaTypeData.attributeMap.get(EAP_AT_AUTN); + byte[] ckIkPrime = deriveCkIkPrime(result, atKdfInput, atAutn); + + int dataToSignLen = MK_DATA_PREFIX.length() + mIdentity.length; + ByteBuffer dataToSign = ByteBuffer.allocate(dataToSignLen); + dataToSign.put(MK_DATA_PREFIX.getBytes(StandardCharsets.US_ASCII)); + dataToSign.put(mIdentity); + + ByteBuffer mk = + ByteBuffer.wrap( + KeyGenerationUtils.prfPlus( + HmacSha256ByteSigner.getInstance(), + ckIkPrime, + dataToSign.array(), + MK_LEN_BYTES)); + + mk.get(mKEncr); + mk.get(mKAut); + mk.get(mKRe); + mk.get(mMsk); + mk.get(mEmsk); + + // Log as hash unless PII debug mode enabled + LOG.d(mTAG, "K_encr=" + LOG.pii(mKEncr)); + LOG.d(mTAG, "K_aut=" + LOG.pii(mKAut)); + LOG.d(mTAG, "K_re=" + LOG.pii(mKRe)); + LOG.d(mTAG, "MSK=" + LOG.pii(mMsk)); + LOG.d(mTAG, "EMSK=" + LOG.pii(mEmsk)); + return null; + } catch (GeneralSecurityException + | BufferOverflowException + | BufferUnderflowException ex) { + LOG.e(mTAG, "Error while generating keys", ex); + return buildClientErrorResponse( + eapIdentifier, getEapMethod(), AtClientErrorCode.UNABLE_TO_PROCESS); + } + } + /** * Derives CK' and IK' values from CK and IK * diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeChallengeStateTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeChallengeStateTest.java index 32041435..a768376f 100644 --- a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeChallengeStateTest.java +++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeChallengeStateTest.java @@ -37,6 +37,7 @@ import static com.android.ike.eap.message.simaka.attributes.EapTestAttributeDefi import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; @@ -79,6 +80,21 @@ public class EapAkaPrimeChallengeStateTest extends EapAkaPrimeStateTest { private static final byte[] EXPECTED_CK_IK_PRIME = hexStringToByteArray( "A0B37E7C7E9CC4F37A5C0AAA55DC87BE51FDA70A9D8F37E62E23B15F1B3941E6"); + private static final byte[] K_ENCR = hexStringToByteArray("15a5bb098528210cde9e8d4a1bd63850"); + private static final byte[] K_AUT = + hexStringToByteArray( + "957b3d518ac9ff028f2cc5177fedad841f5f812cb06e2b88aceaa98129680f35"); + private static final byte[] K_RE = + hexStringToByteArray( + "3c15cf7112935a8170d0904622ecbb67c49dcba5d50814bdd81958e045e42f9c"); + private static final byte[] MSK = + hexStringToByteArray( + "1dcca0351a58d2b858e6cf2380551470d67cc8749d1915409793171abd360118" + + "e3ae271bf088ca5a41bb1b9b8f7028bcba888298bfbf64d7b8a4f53a6c2cdf18"); + private static final byte[] EMSK = + hexStringToByteArray( + "a5e6b66a9cb2daa9fe3867d41145848e7bf50d749bfd1bb0d090257402e6a555" + + "da6d538e76b71e9f80afe60709965a63a355bdccc4e3a8b358e098e41545fa67"); private ChallengeState mState; @@ -296,4 +312,42 @@ public class EapAkaPrimeChallengeStateTest extends EapAkaPrimeStateTest { byte[] result = mState.deriveCkIkPrime(randChallengeResult, atKdfInput, atAutn); assertArrayEquals(EXPECTED_CK_IK_PRIME, result); } + + @Test + public void testGenerateAndPersistEapAkaKeys() throws Exception { + RandChallengeResult randChallengeResult = + mState.new RandChallengeResult(RES_BYTES, IK_BYTES, CK_BYTES); + + AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES); + AtAutn atAutn = new AtAutn(AUTN_BYTES); + AtMac atMac = new AtMac(MAC_BYTES); + AtKdfInput atKdfInput = + new AtKdfInput(0, PEER_NETWORK_NAME.getBytes(StandardCharsets.UTF_8)); + AtKdf atKdf = new AtKdf(VALID_KDF); + + EapAkaPrimeTypeData eapAkaPrimeTypeData = + new EapAkaPrimeTypeData( + EAP_AKA_CHALLENGE, + Arrays.asList(atRandAka, atAutn, atMac, atKdfInput, atKdf)); + + // CK' | IK' = A0B37E7C7E9CC4F37A5C0AAA55DC87BE51FDA70A9D8F37E62E23B15F1B3941E6 + // data = "EAP-AKA'" | Identity + // = 4541502D414B41277465737440616E64726F69642E6E6574 + // prf+(CK' | IK', data) = T1 | T2 | T3 | T4 | T5 | T6 | T7 + // T1 = 15a5bb098528210cde9e8d4a1bd63850957b3d518ac9ff028f2cc5177fedad84 + // T2 = 1f5f812cb06e2b88aceaa98129680f353c15cf7112935a8170d0904622ecbb67 + // T3 = c49dcba5d50814bdd81958e045e42f9c1dcca0351a58d2b858e6cf2380551470 + // T4 = d67cc8749d1915409793171abd360118e3ae271bf088ca5a41bb1b9b8f7028bc + // T5 = ba888298bfbf64d7b8a4f53a6c2cdf18a5e6b66a9cb2daa9fe3867d41145848e + // T6 = 7bf50d749bfd1bb0d090257402e6a555da6d538e76b71e9f80afe60709965a63 + // T7 = a355bdccc4e3a8b358e098e41545fa677897d8341c4a107a2343f393ec966181 + // K_encr | K_aut | K_re | MSK | EMSK = prf+(CK' | IK', data) + assertNull( + mState.generateAndPersistEapAkaKeys(randChallengeResult, 0, eapAkaPrimeTypeData)); + assertArrayEquals(K_ENCR, mStateMachine.mKEncr); + assertArrayEquals(K_AUT, mStateMachine.mKAut); + assertArrayEquals(K_RE, mStateMachine.mKRe); + assertArrayEquals(MSK, mStateMachine.mMsk); + assertArrayEquals(EMSK, mStateMachine.mEmsk); + } } diff --git a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java index c96f3fe2..84f92b42 100644 --- a/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java +++ b/tests/iketests/src/java/com/android/ike/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java @@ -16,6 +16,12 @@ package com.android.ike.eap.statemachine; +import static com.android.ike.eap.statemachine.EapAkaPrimeMethodStateMachine.K_AUT_LEN; +import static com.android.ike.eap.statemachine.EapAkaPrimeMethodStateMachine.K_RE_LEN; +import static com.android.ike.eap.statemachine.EapSimAkaMethodStateMachine.KEY_LEN; +import static com.android.ike.eap.statemachine.EapSimAkaMethodStateMachine.SESSION_KEY_LENGTH; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import com.android.ike.eap.statemachine.EapAkaMethodStateMachine.CreatedState; @@ -27,4 +33,13 @@ public class EapAkaPrimeMethodStateMachineTest extends EapAkaPrimeTest { public void testEapAkaPrimeMethodStateMachineStartState() { assertTrue(mStateMachine.getState() instanceof CreatedState); } + + @Test + public void testKeyLengths() { + assertEquals(KEY_LEN, mStateMachine.getKEncrLength()); + assertEquals(K_AUT_LEN, mStateMachine.getKAutLength()); + assertEquals(K_RE_LEN, mStateMachine.getKReLen()); + assertEquals(SESSION_KEY_LENGTH, mStateMachine.getMskLength()); + assertEquals(SESSION_KEY_LENGTH, mStateMachine.getEmskLength()); + } } |